Pages: [1]   Go Down
Author Topic: if or modulo, what is fastest on AVR?  (Read 2695 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:

//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?
Logged

Norway@Oslo
Offline Offline
Edison Member
*
Karma: 13
Posts: 2033
loveArduino(true);
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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. smiley


Sorry for not answering your question.
Logged

0
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2526
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

0
Offline Offline
Faraday Member
**
Karma: 16
Posts: 2855
ruggedcircuits.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 170
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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.
« Last Edit: October 27, 2009, 10:34:11 am by dentrado » Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

« Last Edit: October 27, 2009, 10:22:31 am by mem » Logged

0
Offline Offline
Faraday Member
**
Karma: 8
Posts: 2526
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26495
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
« Last Edit: October 27, 2009, 10:55:17 am by AWOL » Logged

"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.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 8
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: [1]   Go Up
Jump to: