1

In my embedded system, The following C code will be called in the main by a forever while loop when the system is running. Is there a better way to optimize the following C code so that it doesn't have to go through all the if else statements. I'm thinking is there a better way to make the code run faster since "index" is incrementing every loop by 1. "index" is starting from 0 and incrementing up to 7 and reset back to 0. It is in a repeat pattern.

The reason for the optimization is that the following code need to be run every few micro seconds.

Sample Code below: Note that some of the values are made up.

void main(1)
{
    static int index = 0;

    while (1) {
        if (index == 0) {
            valueA = 0.88;
            valueB = 0.88;
            PID.A0 = 0.0012 * 15;
            PID.A1 = -0.001 * 15;
            index++;
        }
        else if (index == 1) {
            valueA = 0.87;
            valueB = 0.87;
            PID.A0 = 0.0012 * 8;
            PID.A1 = -0.001 * 8;
            index++;
        }
        else if (index == 2) {
            valueA = 0.86;
            valueB = 0.86;
            PID.A0 = 0.0012 * 6;
            PID.A1 = -0.001 * 6;
            index++;
        }
        else if (index == 3) {
            valueA = 0.83;
            valueB = 0.83;
            PID.A0 = 0.0012 * 5;
            PID.A1 = -0.001 * 5;
            index++;
        }
        else if (index == 4) {
            valueA = 0.79;
            valueB = 0.79;
            PID.A0 = 0.0012 * 3;
            PID.A1 = -0.001 * 3;
            index++;
        }
        else if (index == 5) {
            valueA = 0.73;
            valueB = 0.73;
            PID.A0 = 0.0012 * 2;
            PID.A1 = -0.001 * 2;
            index++;
        }
        else if (index == 6) {
            valueA = 0.71;
            valueB = 0.71;
            PID.A0 = 0.0012 * 1;
            PID.A1 = -0.001 * 1;
            index++;
        }
        else if (index == 7) {
            valueA = 0.68;
            valueB = 0.68;
            index = 0;
        }
    }           // end of while()
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
Terry
  • 13
  • 3
  • 3
    Why not switch? Related: https://stackoverflow.com/a/1837986/4123703 – Louis Go Sep 14 '20 at 03:17
  • 1
    What exactly is the target system? – Lundin Sep 14 '20 at 06:54
  • 1
    The question ask: "...to make the code run faster...". With the information given there is no way to answer this question. Without specific information about processor being used, any answer will just be pure guessing. There are many ways to avoid the `if-else if - else if` part of the code but that is not the same as getting "faster execution". – Support Ukraine Sep 14 '20 at 06:55
  • 2
    The very first thing to look at is if this is a Cortex M4 or more powerful. If it is not, then the floating point is a massive bottleneck. Nothing in the code posted indicates an actual need for floating point, this could all have been written in fixed point. – Lundin Sep 14 '20 at 07:02
  • 1
    @Lundin There doesn't seem to be any runtime floating point calculations - just some simple assignments. Therefore I would assume that the use of floating point doesn't really matter. I could be wrong, though... – Support Ukraine Sep 14 '20 at 07:12
  • @4386427 Yeah even if there aren't runtime calculations, the compiler will usually have to link floating point libraries if float is present in the code. This in turn will lead to slower and more memory consuming standard lib calls overall, in particular when it comes to printf-like functions. – Lundin Sep 14 '20 at 08:06
  • 1
    The logic can be changed to "switch with case" statements. However, the end result are pretty much the same after the code translated to assembly. But should use switch statements at the first place. – Terry Sep 15 '20 at 05:39
  • Lundin, the target system is an ARM Cortex M4 MCU. And the code is actually run inside an Interrupt Service Routine This ISR is called or trigger every few microsecond. – Terry Sep 15 '20 at 05:43

2 Answers2

2

You can simplify the logic with a lookup table:

void main(1)
{
    static int index = 0;

    struct {
        double valueA;
        double valueB;
        double PID_A0;
        double PID_A1;
    } values[] = {
        { 0.88, 0.88, 0.0012 * 15, -0.001 * 15 },
        ...
        { 0.68, 0.68, 0, 0 }
    };

    while (1) {
        valueA = values[index].valueA;
        valueB = values[index].valueB;
        if (index != 7) {
            PID.A0 = values[index].PID_A0;
            PID.A1 = values[index].PID_A1;
            index++;
        } else {
            index = 0;
        }
    }
}
dbush
  • 205,898
  • 23
  • 218
  • 273
  • Please note that such a lookup table should be `static const` on embedded systems, or it might end up in RAM instead of flash. – Lundin Sep 14 '20 at 06:56
  • While this code is much more maintainable there no guarantee that it will (quote) "make the code run faster" – Support Ukraine Sep 14 '20 at 06:58
  • Thank you. This is what I'm looking for using lookup table.. It has only one "if else" statement now. I think this method will help if my if else statements keep increasing. The look up table size will increase if more if else (or switch with cases) statements are needed. But the number of CPU instructions will be the same using table lookup method. Which is independent on the number of "if else" statement. Thanks. – Terry Sep 15 '20 at 05:51
  • regarding; `void main(1)` real time systems have a `start.s` or similar function that calls `main()` Therefore, the signature for `main()` should be: `int main( void )` – user3629249 Sep 15 '20 at 15:32
  • the proposed code will result in an extra iteration through the `while()` loop, that does not do anything. The result is the 'saved' values in the struct will not change over the time of two iterations of the `while()` loop – user3629249 Sep 15 '20 at 15:39
0

My first inclination would be a lookup table, such as is presented in @dbush's answer, but you also have the option of unrolling the loop by hand, thereby completely eliminating the conditionals and the index variable:

while (1) {
    valueA = 0.88;
    valueB = 0.88;
    PID.A0 = 0.0012 * 15;
    PID.A1 = -0.001 * 15;

    valueA = 0.87;
    valueB = 0.87;
    PID.A0 = 0.0012 * 8;
    PID.A1 = -0.001 * 8;

    valueA = 0.86;
    valueB = 0.86;
    PID.A0 = 0.0012 * 6;
    PID.A1 = -0.001 * 6;

    valueA = 0.83;
    valueB = 0.83;
    PID.A0 = 0.0012 * 5;
    PID.A1 = -0.001 * 5;

    valueA = 0.79;
    valueB = 0.79;
    PID.A0 = 0.0012 * 3;
    PID.A1 = -0.001 * 3;

    valueA = 0.73;
    valueB = 0.73;
    PID.A0 = 0.0012 * 2;
    PID.A1 = -0.001 * 2;

    valueA = 0.71;
    valueB = 0.71;
    PID.A0 = 0.0012 * 1;
    PID.A1 = -0.001 * 1;

    valueA = 0.68;
    valueB = 0.68;
}           // end of while()
John Bollinger
  • 160,171
  • 8
  • 81
  • 157