Advice and Guidance for my code please?

d10

Member
Hello, I was just wondering if anybody can give me some advice regarding a sketch I am working on. I am trying to optimise for speed first and then memory resource use.

I used pointers to speed everything up. I am under the impression they helps with this. Have I used them pointers correctly.? Does my sketch need this many pointers or do some of them not make a difference or make things worse.

How can I optimise more?

What tips can you give to make the code run more efficiently?

Code:
char print_buffer[40];
const uint8_t lane_size = 4;
const uint8_t lane_amount = 3;
const uint8_t lane_bank_amount = 2;
const uint8_t patch_amount = 8;
const uint8_t data_amount = 2;

uint8_t lane_bank_select = 0;  // This is used to select the data lane bank
uint8_t memory_select = 0;     // This is used to select the data lane bank


struct data_lane {
  uint8_t data1[lane_size];  // This selects which patch is selected..
  uint8_t data2[lane_size];  // reserved for control data
} sceneA[lane_amount], sceneB[lane_amount]; // 2 different versions of data lane

data_lane *dl_ptr[lane_amount] = { 0 };  // pointer for data lanes

uint8_t lane_index[lane_amount] = { 0 };  // index for data lane
uint8_t *lane_index_ptr[lane_amount] = { 0 }; 

// displayed signals
struct patch { // creates banks of data that work together
  uint8_t data1;
  uint16_t data2;
} ptch[patch_amount]; 

patch *ptch_ptr[patch_amount] = { 0 };  // pointer for patches

uint8_t ptch_index[patch_amount] = { 0 };  // index for patch array
uint8_t *ptch_index_ptr[patch_amount] = { 0 };  

void setup() {
  Serial.begin(9600);
}

void loop() {
  serial_lane_select();

  //sets where pointers are pointing to either A or B.
  switch (lane_bank_select) {
    case 0:
      for (uint8_t i = 0; i < lane_size; i = i + 1) {
        dl_ptr[i] = &sceneA[i];
      }
      break;
    case 1:
      for (uint8_t i = 0; i < lane_size; i = i + 1) {
        dl_ptr[i] = &sceneB[i];
      }
      break;
    default:
      for (uint8_t i = 0; i < lane_size; i = i + 1) {
        dl_ptr[i] = &sceneA[i];
      }
      break;
  }

  // fills data into data lanes
  // These signals select when and which signals are displayed

  //SCENE A
  sceneA[0].data1[0] = 1;  // selects ptch[1].data1
  sceneA[0].data1[1] = 0;  // selects ptch[0].data1
  sceneA[0].data1[2] = 0;
  sceneA[0].data1[3] = 0;

  sceneA[1].data1[0] = 2;  // selects ptch[2].data1
  sceneA[1].data1[1] = 1;  // selects ptch[1].data1
  sceneA[1].data1[2] = 1;
  sceneA[1].data1[3] = 1;

  sceneA[2].data1[0] = 3;  // selects ptch[3].data1
  sceneA[2].data1[1] = 2;  // selects ptch[2].data1
  sceneA[2].data1[2] = 2;
  sceneA[2].data1[3] = 2;

  //SCENE B
  sceneB[0].data1[0] = 5;  // selects ptch[5].data1
  sceneB[0].data1[1] = 4;  // selects ptch[4].data1
  sceneB[0].data1[2] = 4;
  sceneB[0].data1[3] = 4;

  sceneB[1].data1[0] = 6;  // selects ptch[6].data1
  sceneB[1].data1[1] = 5;  // selects ptch[5].data1
  sceneB[1].data1[2] = 5;
  sceneB[1].data1[3] = 5;

  sceneB[2].data1[0] = 7;  // selects ptch[7].data1
  sceneB[2].data1[1] = 6;  // selects ptch[6].data1
  sceneB[2].data1[2] = 6;
  sceneB[2].data1[3] = 6;

  //sets where patch pointers are pointing to
  for (uint8_t i = 0; i < patch_amount; i = i + 1) {
    ptch_ptr[i] = &ptch[i];
  }

  // fills data into patches
  // these are the signals that are displayed...
  ptch[0].data1 = 10;
  ptch[0].data2 = 11;
  ptch[1].data1 = 20;
  ptch[1].data2 = 21;
  ptch[2].data1 = 30;
  ptch[2].data2 = 31;
  ptch[3].data1 = 40;
  ptch[3].data2 = 41;
  ptch[4].data1 = 50;
  ptch[4].data2 = 51;
  ptch[5].data1 = 60;
  ptch[5].data2 = 61;
  ptch[6].data1 = 70;
  ptch[6].data2 = 71;
  ptch[7].data1 = 80;
  ptch[7].data2 = 81;


  lane_index[0] = lane_index[0] + 1;
  lane_index[1] = lane_index[1] + 1;
  lane_index[2] = lane_index[2] + 1;
  lane_index_ptr[0] = &lane_index[0];
  lane_index_ptr[1] = &lane_index[1];
  lane_index_ptr[2] = &lane_index[2];

  for (uint8_t i = 0; i < lane_amount; i = i + 1) {
    if (lane_index[i] == lane_size) {
      lane_index[i] = 0;
    }
  }

  ptch_index[0] = (*dl_ptr[0]).data1[*lane_index_ptr[0]];
  ptch_index[1] = (*dl_ptr[1]).data1[*lane_index_ptr[1]];
  ptch_index[2] = (*dl_ptr[2]).data1[*lane_index_ptr[2]];
  ptch_index_ptr[0] = &ptch_index[0];
  ptch_index_ptr[1] = &ptch_index[1];
  ptch_index_ptr[2] = &ptch_index[2];


  sprintf(print_buffer, "L1:%d %d %d %d %d  ",
          *lane_index_ptr[0],
          (*dl_ptr[0]).data1[lane_index[0]],
          *ptch_index_ptr[0],
          (*ptch_ptr[ptch_index[0]]).data1,
          (*ptch_ptr[ptch_index[0]]).data2);
  Serial.print(print_buffer);

  sprintf(print_buffer, "L2:%d %d %d %d %d  ",
          *lane_index_ptr[1],
          (*dl_ptr[1]).data1[lane_index[1]],
          *ptch_index_ptr[1],
          (*ptch_ptr[ptch_index[1]]).data1,
          (*ptch_ptr[ptch_index[1]]).data2);
  Serial.print(print_buffer);

  sprintf(print_buffer, "L3:%d %d %d %d %d  ",
          *lane_index_ptr[2],
          (*dl_ptr[2]).data1[lane_index[2]],
          *ptch_index_ptr[2],
          (*ptch_ptr[ptch_index[2]]).data1,
          (*ptch_ptr[ptch_index[2]]).data2);
  Serial.println(print_buffer);

  return 0;
}


void serial_lane_select() {
  uint8_t recieved;
  if (Serial.available() > 0) {
    recieved = Serial.read();

    if (recieved == '1')  // Single Quote! This is a character.
    {
      lane_bank_select = 0;

      Serial.println("lane_bank 1");
    }

    if (recieved == '2') {
      lane_bank_select = 1;

      Serial.println("lane_bank 2");
    }

    if (recieved == 'q') {
      memory_select = 0;

      Serial.println("memory_bank 1");
    }

    if (recieved == 'w') {
      memory_select = 1;

      Serial.println("memory_bank 2");
    }
  }
}

Thank you very much.
 
Just a few notes:

1. You haven't told us which processor you are using. Compiler efficiency and processor speed for the T4.X CPUs generally means that using pointers versus array indices is not likely to yield large reductions in execution time. Today's compilers are smart enough to minimize the difference in execution time between pointer access and array access.

2. Any improvements in your manipulation of the data will be swamped by the time taken in the sprintf() conversions and Serial.println() calls.

3. If you have code that REALLY needs to be optimized, you should experiment with simple sketches that set up some initial conditions , then run the data manipulation functions multiple times with an elapsedMicroseconds timer used to measure the time in the data manipulation. In your sample code, you would set the timer to zero the start of loop() and capture the elapsed time before the first sprint() call. You could add the elapsed time per loop to a sum, add a loop counter, then print the averaged elapsed time at the end of each loop. When you've got the loop 'instrumented', you can make two separate sketches, on with arrays access and one with pointer access, and look at the difference in average execution time.

4. My initial guess is that you will find little difference in execution time, and your code will be much simpler and easier to maintain if you stick with array access.
 
I am using teensy 4.1.

You could add the elapsed time per loop to a sum, add a loop counter, then print the averaged elapsed time at the end of each loop

can you elaborate on this statement a bit more please i do not understand...

This is what i have so far. Is this correct.

Code:
elapsedMicros sinceTest1; // used to time the sketch
int elapsed = 0;          // captures time of sketch

char print_buffer[40];
const uint8_t lane_size = 4;
const uint8_t lane_amount = 3;
const uint8_t lane_bank_amount = 2;
const uint8_t patch_amount = 8;
const uint8_t data_amount = 2;

uint8_t lane_bank_select = 0;  // This is used to select the data lane bank
uint8_t memory_select = 0;     // This is used to select the data lane bank


struct data_lane {
  uint8_t data1[lane_size];  // This selects which patch is selected..
  uint8_t data2[lane_size];  // reserved for control data
} sceneA[lane_amount], sceneB[lane_amount]; // 2 different versions of data lane

data_lane *dl_ptr[lane_amount] = { 0 };  // pointer for data lanes

uint8_t lane_index[lane_amount] = { 0 };  // index for data lane
uint8_t *lane_index_ptr[lane_amount] = { 0 }; 

// displayed signals
struct patch { // creates banks of data that work together
  uint8_t data1;
  uint16_t data2;
} ptch[patch_amount]; 

patch *ptch_ptr[patch_amount] = { 0 };  // pointer for patches

uint8_t ptch_index[patch_amount] = { 0 };  // index for patch array
uint8_t *ptch_index_ptr[patch_amount] = { 0 };  

void setup() {
  Serial.begin(9600);
}

void loop() {
  sinceTest1 = 0;
  serial_lane_select();

  //sets where pointers are pointing to either A or B.
  switch (lane_bank_select) {
    case 0:
      for (uint8_t i = 0; i < lane_size; i = i + 1) {
        dl_ptr[i] = &sceneA[i];
      }
      break;
    case 1:
      for (uint8_t i = 0; i < lane_size; i = i + 1) {
        dl_ptr[i] = &sceneB[i];
      }
      break;
    default:
      for (uint8_t i = 0; i < lane_size; i = i + 1) {
        dl_ptr[i] = &sceneA[i];
      }
      break;
  }

  // fills data into data lanes
  // These signals select when and which signals are displayed

  //SCENE A
  sceneA[0].data1[0] = 1;  // selects ptch[1].data1
  sceneA[0].data1[1] = 0;  // selects ptch[0].data1
  sceneA[0].data1[2] = 0;
  sceneA[0].data1[3] = 0;

  sceneA[1].data1[0] = 2;  // selects ptch[2].data1
  sceneA[1].data1[1] = 1;  // selects ptch[1].data1
  sceneA[1].data1[2] = 1;
  sceneA[1].data1[3] = 1;

  sceneA[2].data1[0] = 3;  // selects ptch[3].data1
  sceneA[2].data1[1] = 2;  // selects ptch[2].data1
  sceneA[2].data1[2] = 2;
  sceneA[2].data1[3] = 2;

  //SCENE B
  sceneB[0].data1[0] = 5;  // selects ptch[5].data1
  sceneB[0].data1[1] = 4;  // selects ptch[4].data1
  sceneB[0].data1[2] = 4;
  sceneB[0].data1[3] = 4;

  sceneB[1].data1[0] = 6;  // selects ptch[6].data1
  sceneB[1].data1[1] = 5;  // selects ptch[5].data1
  sceneB[1].data1[2] = 5;
  sceneB[1].data1[3] = 5;

  sceneB[2].data1[0] = 7;  // selects ptch[7].data1
  sceneB[2].data1[1] = 6;  // selects ptch[6].data1
  sceneB[2].data1[2] = 6;
  sceneB[2].data1[3] = 6;

  //sets where patch pointers are pointing to
  for (uint8_t i = 0; i < patch_amount; i = i + 1) {
    ptch_ptr[i] = &ptch[i];
  }

  // fills data into patches
  // these are the signals that are displayed...
  ptch[0].data1 = 10;
  ptch[0].data2 = 11;
  ptch[1].data1 = 20;
  ptch[1].data2 = 21;
  ptch[2].data1 = 30;
  ptch[2].data2 = 31;
  ptch[3].data1 = 40;
  ptch[3].data2 = 41;
  ptch[4].data1 = 50;
  ptch[4].data2 = 51;
  ptch[5].data1 = 60;
  ptch[5].data2 = 61;
  ptch[6].data1 = 70;
  ptch[6].data2 = 71;
  ptch[7].data1 = 80;
  ptch[7].data2 = 81;


  lane_index[0] = lane_index[0] + 1;
  lane_index[1] = lane_index[1] + 1;
  lane_index[2] = lane_index[2] + 1;
  lane_index_ptr[0] = &lane_index[0];
  lane_index_ptr[1] = &lane_index[1];
  lane_index_ptr[2] = &lane_index[2];

  for (uint8_t i = 0; i < lane_amount; i = i + 1) {
    if (lane_index[i] == lane_size) {
      lane_index[i] = 0;
    }
  }

  ptch_index[0] = (*dl_ptr[0]).data1[*lane_index_ptr[0]];
  ptch_index[1] = (*dl_ptr[1]).data1[*lane_index_ptr[1]];
  ptch_index[2] = (*dl_ptr[2]).data1[*lane_index_ptr[2]];
  ptch_index_ptr[0] = &ptch_index[0];
  ptch_index_ptr[1] = &ptch_index[1];
  ptch_index_ptr[2] = &ptch_index[2];

  elapsed = sinceTest1; // captures time at end of loop

  Serial.print(elapsed); Serial.print(" ");


  sprintf(print_buffer, "L1:%d %d %d %d %d  ",
          *lane_index_ptr[0],
          (*dl_ptr[0]).data1[lane_index[0]],
          *ptch_index_ptr[0],
          (*ptch_ptr[ptch_index[0]]).data1,
          (*ptch_ptr[ptch_index[0]]).data2);
  Serial.print(print_buffer);

  sprintf(print_buffer, "L2:%d %d %d %d %d  ",
          *lane_index_ptr[1],
          (*dl_ptr[1]).data1[lane_index[1]],
          *ptch_index_ptr[1],
          (*ptch_ptr[ptch_index[1]]).data1,
          (*ptch_ptr[ptch_index[1]]).data2);
  Serial.print(print_buffer);

  sprintf(print_buffer, "L3:%d %d %d %d %d  ",
          *lane_index_ptr[2],
          (*dl_ptr[2]).data1[lane_index[2]],
          *ptch_index_ptr[2],
          (*ptch_ptr[ptch_index[2]]).data1,
          (*ptch_ptr[ptch_index[2]]).data2);
  Serial.println(print_buffer);

  return 0;
}


void serial_lane_select() {
  uint8_t recieved;
  if (Serial.available() > 0) {
    recieved = Serial.read();

    if (recieved == '1')  // Single Quote! This is a character.
    {
      lane_bank_select = 0;

      Serial.println("lane_bank 1");
    }

    if (recieved == '2') {
      lane_bank_select = 1;

      Serial.println("lane_bank 2");
    }

    if (recieved == 'q') {
      memory_select = 0;

      Serial.println("memory_bank 1");
    }

    if (recieved == 'w') {
      memory_select = 1;

      Serial.println("memory_bank 2");
    }
  }
}

All i get from the elapsed variable is mostly zeros with the odd random 1 appearing. does this mean the sketch takes at most 1 microsecond?
 
Back
Top