AMIGA alive

AMIGA alive

Tuesday, October 5, 2021

AADevLog #1 - xiffview 0.4, CLI 3d-printing, and a little bit of research

Over the last few months I've looked into several different subjects with no particular focus, but I got some results nontheless.

You might have seen the latest release of xiffview (v0.4), my little IFF ILBM picture viewer for Linux. It's a side product, created to simplify development for the Amiga, but I have a couple of further ideas to turn it into a really useful tool, e.g. add cropping, bitplane manipulation, etc. Anyway, for now it has learned something about palettes and sprites - see AmiNet readme file.

Another side product of some hardware changes happening in my workplace is a CLI controlled .gcode 3d-printing program written in quite Amiga-ish C code, which I call "reprint". It's currently very beta, and for Linux, but it successfully sends g-code to the printer - maybe another brick in building 3d-printing support for the Amiga? Some day I'll try to wire up something, then recompile "reprint" for Amiga, and keep my fingers crossed. ;-)

And then there's this little question that's been nagging me for years: when writing C code, is it good practice to copy stuff to local vars?

Here's what I mean by that: I have a tendency to create a large struct that holds my program's data, settings, pointers, etc., then access that data as members of that struct, e.g. in (inner) loops. I always wonder if this creates a complicated set of CPU instructions when compiled to assembler, esp. when accessing "deep" members - thus if it would be better to copy member data from global struct to a local variable, then use that variable e.g. in (inner) loops.

For single access this is obviously not an issue - but what about repeatedly accessing such member data? So I did some actual testing.

Looking at this piece of repeatedly struct-member-accessing (pseudo) C code...

for (loops) { n = some_pointer->some_member.some_number; }

...and comparing it to this piece of (pseudo) C code, which first copies to local var, ...

my_n = some_pointer->some_member.some_number;
for (loops) { n = my_n; }

...one would probably assume it's obvious the latter version is faster, because the code inside the loop looks vastly simpler. On the other hand someone somewhere suggested it wouldn't make a (noticeable) difference due to compiler optimization.

After a few test runs (pretty much using the pseudo code above), I think it can indeed be considered good practice to copy to local var. Results vary strongly, esp. on my 8-core Linux machine, but on the Amiga the latter version of the code is near-consistently about 25% faster than the former. With the struct member inside the loop, the compiler, or someone else, obviously didn't see we're accessing the same data over and over again. There are probably a hundred things to keep in mind, e.g. loop-size vs. CPU cache, size of struct, location of member, amount of data, compiler abilities, etc., - but it looks as if copying data to local var should indeed be preferred. Under certain circumstances it executes faster, and in most cases it's much more readable and saves a lot of typing.

What do you think? Any experience, opinion?

C u next time!

No comments:

Post a Comment