Strange execution times on test case.

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am trying to test a function 'funn' (a lowpass filter) that I implementet:

 

void inline funn( int16_t in, int16_t& out, uint8_t midiCC );

 

variable in' is the stream, 'out' is the result and 'midiCC' is a variable that changes the centre frequency.

 

-------------------------------

 

The test case is:

 

void testing(uint8_t midiCC)
{
  int num_of_iter = 100;
  uint32_t beforeMillis = millis();
  uint32_t nextMillis = millis();
  
  Serial.print("midiCC: "); Serial.println(midiCC);
  
  beforeMillis = millis();
  for(size_t k = 0 ; k < num_of_iter ; ++k)
    for(size_t i = 0 ; i < len ; ++i)
      funn(inputs[i],out,midiCC);
  nextMillis = millis();
  
  Serial.print("funn: "); Serial.println(nextMillis-beforeMillis);
  Serial.print("test"); Serial.println(out);
  Serial.println("");
  
  delay(1000);
}

void loop() {
  testing(0);
  testing(10);
  testing(50);
  testing(100);
  testing(120);
  testing(127);
}

 

Variable 'test' is just so the compiler does not optimize anything away.

Variable 'inputs' is just a big array that you could see as a square wave.

Variable 'iout' the momentan value.

 

----------------------

 

Question, I got some strange result:

 

midiCC: 0
funn: 39
test1000

 

midiCC: 10
funn: 52
test1021

 

midiCC: 50
funn: 57
test1483

 

midiCC: 100
funn: 86
test2909

 

midiCC: 120
funn: 108
test3635

 

midiCC: 127
funn: 108
test2939

 

The time () it that takes to execute increments when 'midiCC' increments.

Could argue that it is a loop in the implementation but where are none.

 

I have no idea why it is not constant time.

 

//returns uint16in multiplied with uint8in gnoring the least significan byte.
inline uint16_t mulu8x16div8_16(uint8_t uint8in, uint16_t uint16in)
{
  uint16_t res;
  asm volatile (
  "clr %B0 \n\t"
  "mul %A1, %A2 \n\t"
  "mov %A0, __zero_reg__ \n\t"
  "mul %A1, %B2 \n\t"
  "add %A0, __tmp_reg__ \n\t"
  "adc %B0, __zero_reg__ \n\t"
  "clr r1 \n\t"
  :
  "=&r" (res)
  :
  "a" (uint8in),
  "a" (uint16in)
  );
  return res;
}


void inline funn( int16_t in, int16_t& out, uint8_t midiCC )
{
  if(midiCC < 1) { out = in; return; }
  else if(in==out) { return; }
  midiCC <<= 1;
  midiCC = ~midiCC; // 0-127 => 255-0
  int16_t o = (in - out);
  int16_t c;
  if(o > 0)
  {
    //out += (int16_t) midiCC;
    c = mulu8x16div8_16( midiCC , o );
    if(!c) c = 1;
  }
  else
  {
    //out -= (int16_t) midiCC;
    c = - mulu8x16div8_16( midiCC , -o );
    if(!c) c = -1;
  }
  out += c;
}

 

Running Arduino 1.8.2 

Microchip: atmega32u4

 

Last Edited: Thu. Oct 12, 2017 - 05:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The code is not in code tags.

len does not appear to be defined.

The inline assembly is a horror of obfuscation.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ahh sorry! I tried to keep the explanation short forgot about 'len'.

I have 'len' defined.

 

This is my globals and setup() 

 

uint8_t factor = 100;
size_t i = 0;
size_t len = 256;
int16_t inputs[256];
int16_t out;

void setup() {
  uint16_t sample[] = { 4095, 1000, 4095, 1500};
  size_t y = 0;
  size_t z = 0;
  for(size_t x = 0; x  < len ; ++x)
  {
    if(++z > 50)
    {
      z = 0;
      ++y;
    }
    if(y>3) y = 0;
    inputs[x] = sample[y];
  }
  Serial.begin(9600);
}

-------------

 

The assembly is whery simple. It is unsigned char multiplied with unsigned int and then remove the most significant byte.

One chould say that I scale the uint16in with uint8in.

Will give the same result in C.

 

inline uint16_t mulu8x16div8_16(uint8_t uint8in, uint16_t uint16in)
{
  return (  ((uint32_t) uint8in  )  *  ((uint32_t) uint16in  )  >> 8 );
}

 

Ecit in a comments about the assebly now to my former post.

 

But that will become more operatons and bigger hex file.

Trying to avoid uint32_t calculations.

 

And I have tested the assembly code seperate with different values. Time is constant and gives correct results.

 

Last Edited: Thu. Oct 12, 2017 - 04:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DONE, fanx.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I finally found it!!

 

It is the compiler that manage to do some optimization.

 

Inside 'funn' is the code:

    //out += (int16_t) midiCC;
    c = mulu8x16div8_16( midiCC , o );
    if(!c) c = 1;

When I remove the line

if(!c) c = 1;

I get a fixed execution time that is higher.