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

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

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