About the Arduino calculation speed

HI. I watched the arduino calculation speed tables.

This might be a very stupid question but not sure about the answer.
Let's suppose I write simple code like this in void loop.

a = digitalRead(input); // expect to take 1s to read and save value of input to a.
digitalWrite(output, a); //expect to take 0.5s to make output pin have signal of a.
Serial.println(a); // expect to take 0.5s to print the value of a on the serial monitor.

(Those latency(?) is not the real arduino's spec but just for example)

Now when the code start to begin, it will take 1s to store input value to a.

Did the second code(later) executed after the 1st code fully did their job? I mean, did they
wait until the input value stored into a or they just executed regardless of the previous code calculation end?

The C/C++ compiler has many options, and can optimize the machine code to do things in different orders and different speeds of execution, depending on your choice of settings.

Regardless, you can be assured that when you output or print the value of "a", it will represent the result of reading the digital input.

where I wanted to make many operations in less than 30 microseconds.

That depends on the type of processor you choose, and processor clock frequency.

Yes
Your statements are executed in sequence and will be completed before the next statement is executed. But be aware with e.g. the print statements.

When you use them, they will write data to a buffer in software and will hardly take any real time. There is an underlaying mechanism (interrupts) to send the data actually out and that still needs time (e.g. at 9600 baud roughly 1 millisecond per byte).

If that buffer fills up and the print statement can no longer place bytes in the buffer, it will wait till it can place the next byte in the buffer.

In C++, the compiler may optimise code, including reordering code lines, to improve performance or reduce code size, so this is not always the case.

However, when using functions like digitalRead() and digitalWrite() , the compiler typically respects the order of these function calls as they interact directly with hardware pins and the functions are implicitly marked as volatile.

So indeed, in this specific case the 3 lines will be executed in sequence.

Thanks!! thats a lot of help

One second to read and save with digital read? More like 5 microseconds the slow way! Whoever wrote that comment doesn't know much!

Arduino digital read and write are fool-safed, slower than direct register manipulation functions.
IF you take care to not do wrong things, direct port manipulation is about 5x faster. Wrong takes some doing, usually setting pin mode then doing the same thing over and over is safe but learn what not to do and you won't screw up!
Search words are direct port manipulation, you can find better instructions than a post I would write! Others here may post links even.

Other calculation speed tricks are hardware specific. On 8-bit AVR's the small variable types work faster when values fit, for example.
Where the is no FPU (most all Arduino's and compatibles) it is better to work with integers than floats (except for powers of 10 multiply/divide).
If I want meters to 3 places with some divides, I make my work units micrometers, 1 meter = 1000000 micrometers, and then I can lose 3 places and still be millimeter-accurate using 32 bit integers.

Another fast match trick is to use lookup tables of pre-calculated values and if necessary, interpolate. Arduino flash has lots of room to spare if your code isn't bloated, looking up sine values is insanely faster than using float sine function even with interpolation but still use integers and small units for more speed.

Lookup tables is how basic flight sims ran on 80's 6502 computers At All. The more pre-calculation you can pack into table values the less run time calculations you have to do!
To that end, even working tables in SD files should beat thrashing formulae on the CPU! It is also possible to hang serial RAM on the SPI bus to get more RAM for speed tradeoff depending on situation.

And if you need faster, get an AMD-uino like the 600 MHz Teensy 4.1 that has an FPU, loads of RAM and built-on SD slot!

So you were saying about speed?

I know that the compiler has a lot of freedom although I do not know exactly which freedoms. One of the things is that it might throw away stuff that it considers as not-needed.

But I have great difficulty believing that the end result is not the sequence in which the C++ statements were ordered in the code. It would be a big mess if I clear memory using memset and next fill it with e.g. Serial.read() and the compiler will first fill and next will clear the memory. It might throw away the clearing of the memory if it realises that the fill will always be exactly the same size as the clearing of the involved memory.

I have looked enough at listings from avr-objdump to know that a function call not necessarily results in a call but in a jump in assembly or the call is completely skipped as in below example.

int main(void)
{
    5fb2:	cf 93       	push	r28
    5fb4:	df 93       	push	r29
    5fb6:	cd b7       	in	r28, 0x3d	; 61
    5fb8:	de b7       	in	r29, 0x3e	; 62
    5fba:	61 97       	sbiw	r28, 0x11	; 17
    5fbc:	0f b6       	in	r0, 0x3f	; 63
    5fbe:	f8 94       	cli
    5fc0:	de bf       	out	0x3e, r29	; 62
    5fc2:	0f be       	out	0x3f, r0	; 63
    5fc4:	cd bf       	out	0x3d, r28	; 61

void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();
    5fc6:	78 94       	sei

...
...
    6048:	10 92 c1 00 	sts	0x00C1, r1	; 0x8000c1 <__DATA_REGION_ORIGIN__+0x61>

void HardwareSerial::begin(unsigned long baud, byte config)
{
  // Try u2x mode first
  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
  *_ucsra = 1 << U2X0;
    604c:	e0 91 2e 04 	lds	r30, 0x042E	; 0x80042e <Serial+0x10>
    6050:	f0 91 2f 04 	lds	r31, 0x042F	; 0x80042f <Serial+0x11>

This is from (part of) the listing of Neopixel interrupting CanBus : Project Problem - #6 by skyspect in case you're interested.

1 Like

This principle is known as the "as-if" rule.

Under the "as-if" rule, a compiler is permitted to reorder statements, eliminate redundant code, and perform other optimizations as long as the end result behaves as if the program had been executed exactly as written by the programmer. This means that the compiler can rearrange statements for performance reasons, but it must ensure that the program's output remains consistent with the original code.

so if you write

int a = 0, b = 10, c = 20;

a += 10;
b += 10;
c += 10;

Serial.println(a);
Serial.println(b);
Serial.println(c);

the compiler can decide to reorder the way a, b and c are incremented

int a = 0, b = 10, c = 20;

c += 10;
b += 10;
a += 10;

Serial.println(a);
Serial.println(b);
Serial.println(c);

or can decide to do the maths and make the assignment with the expected value ie, generate

int a = 10, b = 20, c = 30;

Serial.println(a);
Serial.println(b);
Serial.println(c);

or even generate (if you don't use a, b, c later)

Serial.println(10);
Serial.println(20);
Serial.println(30);

as the end result behaves as if the program had been executed exactly as written by the programmer.

1 Like

I think that I should have phrased my point slightly different. Thanks for the link and the example.

High end processors with multiple execution units (think Intel or AMD PCs) can reorder the execution order or execute operations in parallel in hardware as long as the result is "as If" they were done in order.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.