Would an infinite loop inside loop() perform faster?
The part of the code on an ATmega core that does setup() and loop() is at follows:
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Pretty simple, but there is the overhead of the serialEventRun(); in there.
Let's compare two simple sketches:
void setup()
{
}
volatile uint8_t x;
void loop()
{
x = 1;
}
and
void setup()
{
}
volatile uint8_t x;
void loop()
{
while(true)
{
x = 1;
}
}
The x and volatile is just to ensure it isn't optimised out.
In the ASM produced, you get different results:
You can see the while(true) just performs a rjmp (relative jump) back a few instructions, whereas loop() performs a subtraction, comparison and call. This is 4 instructions vs 1 instruction.
To generate ASM as above, you need to use a tool called avr-objdump. This is included with avr-gcc. Location varies depending on OS so it is easiest to search for it by name.
avr-objdump can operate on .hex files, but these are missing the original source and comments. If you have just built code, you will have a .elf file that does contain this data. Again, the location of these files varies by OS - the easiest way to locate them is to turn on verbose compilation in preferences and see where the output files are being stored.
Run the command as follows:
avr-objdump -S output.elf > asm.txt
And examine the output in a text editor.
Cybergibbons's answer describes quite nicely the assembly code generation and the differences amongst the two techniques. This is intended to be a complementary answer looking at the issue in terms of practical differences, i.e. how much of a difference either approach will make in terms of execution time.
Code Variations
I did an analysis involving the following variations:
- Basic
void loop()
(which gets inlined on compilation) - Un-inlined
void loop()
(using__attribute__ ((noinline))
) - Loop with
while(1)
(which gets optimized) - Loop with un-optimized
while(1)
(by adding__asm__ __volatile__("");
. This is anop
instruction that prevents optimization of the loop without resulting in additional overheads of avolatile
variable) - An un-inlined
void loop()
with optimizedwhile(1)
- An un-inlined
void loop()
with un-optimizedwhile(1)
The sketches can be found here.
Experiment
I ran each of these sketches for 30 seconds, thereby accumulating 300 data points each. There was a 100 millisecond delay
call in each loop (without which bad things happen).
Results
I then calculated the mean execution times of each loop, subtracted 100 milliseconds from each and then plotted the results.
http://raw2.github.com/AsheeshR/Arduino-Loop-Analysis/master/Figures/timeplot.png
Conclusion
- An un-optimised
while(1)
loop withinvoid loop
is faster than a compiler optimisedvoid loop
. - The time difference between the un-optimized code and default Arduino optimized code is insignificant practically. You will be better off compiling manually using
avr-gcc
and using your own optimisation flags rather than depending on the Arduino IDE to help you with it (if you need microsecond optimisations).
NOTE: The actual time values are not of significance here, the difference between them is. The ~90 microseconds of execution time includes a call to Serial.println
, micros
and delay
.
NOTE2: This was done using the Arduino IDE and the default compiler flags that it supplies.
NOTE3: Analysis (plot and calculations) was done using R.