Go Down

Topic: if or modulo, what is fastest on AVR? (Read 3049 times) previous topic - next topic

dentrado

I am building a binary alarm clock and I wonder what is the fastest to use in the code, modulo and divide or if's.

I used the same model as here for timekeeping:
Code: [Select]

current_millis_value = millis();
 m += current_millis_value - previous_millis_value;
 seconds += m / 1000;
 m = m % 1000;
 minutes += seconds / 60;
 seconds = seconds % 60;
 hours += minutes / 60;
 minutes = minutes % 60;
 hours = hours % 24;
 previous_millis_value = current_millis_value;


As you can see it uses lot's of % and /. Is this because it's faster or just because it's easier to read? Maybe it's actually slower with modulo (and divides), according to this post, modulo is quite slow.

For example, is there a big difference in clock cycles used for these two examples that are saving the end-time of the 10min snooze-period (current time + 10 minutes)?:

Code: [Select]


//modulo alternative:
if(buttonPressed)
{            
   snoozeHours = hours;
   snoozeHours += (minutes+10)/60; // if snooze minutes is more than 60 add 1 to hours
   snoozeMinutes = (minutes+10)%60; // and substract 60 from the snooze minutes
}

// if alternative:
if(buttonPressed)
{      
     if(minutes<50)
     {
         snoozeMinutes = minutes+10;
         snoozeHours = hours;
     else
     {
        snoozeMinutes = minutes-50; // or minutes+10-60
        snoozeHours = hours+1;
     }
}
 


Maybe somebody with better knowledge than me on AVR processors can answer?

AlphaBeta

My first thought is that you do not need to worry about this if you only need a resolution of one second.
Then you have plenty of time to process (other) things. :)


Sorry for not answering your question.

kg4wsv

As a general rule, you should code what is correct and readable, and stay out of the compiler's way while it makes the code fast.

If you find out that isn't fast enough, then start looking at hand optimization.

-j

RuggedCircuits

Agree with all of the above, but for the sake of answering your question, divisions and modulos are going to be a lot slower than if-statements on the AVR architecture.

Kitep

I don't know which is faster, but if you wrote a sketch that runs a for loop about 10 millions times (or a billion, or whatever) doing it one way, you could time it.  Then do it the other way, and see which comes in faster.

Good luck!

dentrado

Thanks for all the answers, yes you are maybe right that it doesn't matter much which method I use, but there will be alot more in the loop than the clock code. I will use capacitive sensors (link) as buttons and play some melody on a piezo element when the alarm goes off etc.

I think I'll try with divisions and modulo first and rewrite if there is problems.

@RuggedCircuits, Thanks, it's always good to know how it is, if I need to, I know what i could try to optimize.

@Kitep, yeah it would be intresting to see how big the diffrence is, maybe I should do a test.

dentrado

#6
Oct 27, 2009, 03:46 pm Last Edit: Oct 27, 2009, 04:34 pm by dentrado Reason: 1
I know this thread is quite old, but I have made a test now. The result was that the clockfunction with if's was 15,5 times faster than the modulo version.

i ran it 10000 times each and timed it, the modulo version took almost 1.5 seconds (ca 1470 millis) and the if version ca 95 milliseconds.

Here is the functions I used:
Code: [Select]

// CLOCK VARIABLES:
#define MAX_MILLIS_VALUE 34359738
unsigned long current_millis_value = 0;
unsigned long previous_millis_value = 0;
unsigned long m = 0;
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;

void moduloClock()
{
 cli(); // disable interrupts*
 current_millis_value = millis();
 sei(); // enable interrupts*
 if (current_millis_value < previous_millis_value) // if millis overflows
 {
   m += MAX_MILLIS_VALUE - previous_millis_value + current_millis_value;
 }
 else // if millis has not overflown
 {
   m += current_millis_value - previous_millis_value;
 }
 seconds += m / 1000;
 m = m % 1000;
 minutes += seconds / 60;
 seconds = seconds % 60;
 hours += minutes / 60;
 minutes = minutes % 60;
 hours = hours % 24;
 previous_millis_value = current_millis_value;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *= "Also, you should disable interrupts while calling millis(),         *
* otherwise you run the risk of getting corrupted data should the         *
* timer0 overflow occur while millis() is performing its computation"     *
* source: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1215338347/0#1  *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
}

/* Clock function that uses if statements instead of modulo */
void ifClock()
{
 cli(); // disable interrupts
 current_millis_value = millis();
 sei(); // enable interrupts
 if (current_millis_value < previous_millis_value) // if millis overflows
 {
   m += MAX_MILLIS_VALUE - previous_millis_value + current_millis_value;
 }
 else // if millis has not overflown
 {
   m += current_millis_value - previous_millis_value;
 }
 if (m>999) /* if m is 1000 or over  */
 {
   seconds++;
   m = m-1000;
 }
 if (seconds>59) /* if seconds == 60 */
 {
   minutes++;
   seconds = 0;
 }
 if (minutes>59) /* if minutes == 60 */
 {
   hours++;
   minutes = 0;
 }
 if (hours>23) /* if hours == 24 */
 {
   hours = 0;
 }
 
 previous_millis_value = current_millis_value;
}


Edit: fixed an error in the code and added some comments.

mem

#7
Oct 27, 2009, 04:19 pm Last Edit: Oct 27, 2009, 04:22 pm by mem Reason: 1
I see in your code that you are disabling interrupts before calling millis, You don't need to do that, millis does that for you.

BTW, I would expect you would get different numbers if you had used bytes instead of ints for your hour, minute and seconds variables

Also, I agree with the sentiments expressed by AB, kg and RC that its better to use what makes the most readable and logical source code and not worry about optimization until you really need to.


kg4wsv

Wow, a factor of 15 is a big difference.

Wish I had time to look at the assembly resulting from your code to see what's happening.

A quick glance at the instruction set for the ATmega indicates there is no integer divider instruction?  If integer division is implemented in software, that certainly explains the difference as you're doing a lot of division.  The "if" version also does far fewer memory transfers (writes to memory on rollover, not every time).

-j

AWOL

#9
Oct 27, 2009, 04:53 pm Last Edit: Oct 27, 2009, 04:55 pm by AWOL Reason: 1
Quote
A quick glance at the instruction set for the ATmega indicates there is no integer divider instruction?

Pretty rare on microcontrollers of this size - there's rarely even a multiply!
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

dentrado

Quote

I see in your code that you are disabling interrupts before calling millis, You don't need to do that, millis does that for you.

Ok, thanks for the info.

Quote

BTW, I would expect you would get different numbers if you had used bytes instead of ints for your hour, minute and seconds variables

true, perhaps I should try that too just for fun.

Quote

Also, I agree with the sentiments expressed by AB, kg and RC that its better to use what makes the most readable and logical source code and not worry about optimization until you really need to.

I agree too, however in this case I think both versions are very readable, the modulo version is certainly shorter, but the if version is easy to follow, and for a person new in programming I think the modulo version can be a little confusing at first.

Go Up