Speed, does the order of functions matter?

Hi,

I remember from my times into (Applesoft)-BASIC programming that the order in which you put the subroutines mattered for the speed of execution of the software. In BASIC the shortest subroutines (or the subroutines most used) had to be at the bottom of the software for fastest execution.

Does this order matter for the functions in Arduino/C++?

Does this order matter for the functions in Arduino/C++?

Not in the slightest.

It depends, for calling the function it does not matter where C functions are as they are compiled code. Basic was interpreted and a call to a function meant the interpreter had to search for the function in the source code. Beside slower execution this also caused that most errors only were detected runtime.

However if you look in which order the functions are called - not the physical place in the code but their logical place in the system design - the effect can be quite dramatic. Simple example is when you want to filter a stream on a number of criteria and every criteria has its own (filter) function. For optimal efficiency you must put the "strongest" criteria as first and the "weakest" as last filter. This is a science in itself e.g. for optimizing (complex) database queries a database evaluates different execution plans to optimize performance. Also for backtracking algorithms pruning the search tree asap makes code way faster.

ON5MF:
Hi,

I remember from my times into (Applesoft)-BASIC programming that the order in which you put the subroutines mattered for the speed of execution of the software. In BASIC the shortest subroutines (or the subroutines most used) had to be at the bottom of the software for fastest execution.

Does this order matter for the functions in Arduino/C++?

Generally for the level Arduinos run at, it does not matter. A function is placed at an absolute address, and the linker replaces the data field of the call with the address. So no matter where you are calling, it is a fixed address.

Now, in the world of high performance machines, where you have multiple levels of caching, it does occasionally matter, and it can be tricky to resolve it. Generally, it only matters in a few cases, such as in the super computer world where you have thousands of cores/processors all running the same code. Some of the cases I’ve seen over the years include:

  • On some architectures, the native call instruction has a limited size field to represent the function address. If your program is so large, that you cannot encode the call directly, the linker will generate a stub that jumps to the function using more instructions, and then modify the call instruction to call the stub. Here the solution is to move calls that are on the critical path so they are close enough to be able to use the call instruction.
  • On some architectures, if you have several functions that are called frequently enough, and by chance they are lined up on the same instruction cache boundary, and going between the two makes the cache thrash. This is rather tricky to solve (or even diagnose).
  • Depending on the alignment, a function could be placed so that it crosses page boundaries in the middle of the hot loop, and moving it slightly helps.

However, most Arduino code is not limited by such micro level details. If you find yourself needing more cycles, rather than doing extensive bit banging, the first solution is just get a faster processor. The AVR runs at 8 Mhz or 16 Mhz, and you can get low power Arm processors that run at 48 Mhz or 96 Mhz. In addition, something like an Arm will do arithmetic in fewer instructions than an AVR because the Arm is 32-bit and the AVR is 8-bit. Particularly if you are using floating point extensively, just getting a chip that has hardware floating point will speed things up tremendously.

In any case, it is the linker that decides where to put the functions, not where they are in the source code. The linker could put them in alphabetical order!

Can you inline functions for the arduino?

ON5MF: Does this order matter for the functions in Arduino/C++?

The closest feature of 'C'/C++ relating to that is that functions, types and variables need to be declared before they are used, where 'before' refers to the order of definitions within the file. At any given point in a 'C'/C++ source file, the declarations and definitions above you are available for use, and the declarations and definitions below you are not. Typically, you would insert declarations for everything at the top of the file (or in a header file included at the top of the file) so that the order of definitions didn't matter. However, if you order the definitions so that no code in the file refers to definitions which below it in the file then you wouldn't need to add the declarations.

So, this compiles:

// foo.cpp
void a()
{
}

void b()
{
  a();
}

This doesn't:

// foo.cpp
void b()
{
  a(); // at this point, a() has not been declared
}

void a()
{
}

One quirk of the Arduino IDE is that sketch files are pre-processed by the IDE and it inserts declarations at the top of the file for all the definitions in the file, so that you don't need to explicitly add them yourself. However:

  • The IDE only does this for the sketch .ino file, not any other .c/.cpp files included in your project
  • The algorithm used to insert the declarations is not very good and sometimes it screws up