strange and supicious behaviour of embedded coder for generated code optimization

5 views (last 30 days)
Hello,
I am currently trying to optmize performances of the C code generated by Embedded Coder for MATLAB R2918b and I do not understand some strange behaviour of this process.
As a matter of fact, I have noticed that some MATLAB code using operations between complex vector and single do not lead to code I expected to see.
For example, let us examine the following MATLAB function:
y = fcn()
fIn = single(100.0 * (rand(1, 327680)+ 0.5));
divider = single(360.0);
fOut = (1i * fIn)/divider;
y = nom(fOut);
end
Then the code generated by Embedded Coder includes the following strange lines (knowing that b[] is calculated as random real values between 0 and 1):
d_0.re = 0.0F;
d_0.im = 0.0F
for (i = 0; i < 32768; i++) {
ai = (real32_T)((b[i] + 0.5) * 100.0);
if (ai == 0.0F) {
d[i].re = 0.0F;
d[i].im = 0.0F;
} else {
d[i].re = 0.0F
d[i].im = ai / 360.0F;
}
}
The same behaviour occurs when input vector "fIn" is a simple ramp from 1.0 to 100.0 or any input single vector coming from somewhere else. And in the latter case, it is very often the case in real life that values for a real signal is very closed to 0.0F but not truly 0.0F; testing a single value against 0.0F for real data seems not very clever and as a result, the condition (ai == 0.0F) may never be true.
Obviously in my example, aI is never equal to 0.0F as its minimal value can (very rarely) be 50.0; thus the condition (ai == 0.0F) is never true and the generated code is testing 32768 times a useless condition. This is not very perfoming compared with manual coding (which is often the case I must admit).
Besides, this behaviour can be confirmed by producing code coverage; in the coverage report, I could see that the lines "d[i].re = 0.0F; d[i].im =0.0F" are never reached.
I would have preferred to see a straight forward generated code like this:
for (i =0; i < 32768;i++) {
ai = (real32_T)((b[i] + 0.5) * 100.0);
d[i].re = 0.0F
d[i].im = ai / 360.0F;
}
Now my question is:
Is there any option for generated code optimization (or any other trick) to avoid producing useless condition "if (ai == 0.0F)" ?
Thank you for your attention.
Best regards.

Answers (5)

Jonas
Jonas on 11 Aug 2020
Edited: Jonas on 11 Aug 2020
Check your Embedded Coder Configuration Settings. You can for example try to check 'Inline invariant signals' and set the 'Default parameter behaviour' to 'Inlined' to make sure Embedded Coder sees your variable 'divider' as invariant. From your original code, the line 'fOut = (1i * fIn)/divider;' can give issues and the coder needs to protect it against division by zero. Of course, the variable divider is always fixed to 360.0 but the Configuration Parameters you have at the moment do not allow inlining this value.
There may be other Configuration Parameters which are helpful but I would need to test/try them myselves to see the effect on the code. It's under Configuration Parameters > Code Generation > Optimization > Advanced parameters.

Didier Billard
Didier Billard on 11 Aug 2020
Hello Jonas,
First thank you very much for your message.
Alas, considering my Simulink test model, it appears that "Default parameter behavior" is set to "inlined" and "Inline invariant signals" is checked already.
And looking at the generated code, I can confirm that "divider" variable has been replaced by fixed value 360.0F and is not declared anywhere.
Besides, what I am worrying about is not the possible division by zero but the conditional test "if (ai == 0.0F)" which is never true in my case.
Nevertheless I thank you again for your support.
Best regards.
  1 Comment
Jonas
Jonas on 11 Aug 2020
Is your setting for 'Remove code that protects against division arithmetic exceptions' checked? Could you maybe share a screenshot of this Configuration Parameters page, for the 'Advanced parameters'?

Sign in to comment.


Didier Billard
Didier Billard on 11 Aug 2020
Hello Jonas,
Please fin attached a capture of Simulink test model configuration.
Best regards.

Didier Billard
Didier Billard on 12 Aug 2020
Edited: Walter Roberson on 12 Aug 2020
Hello,
I cannot understand the way Embedded Coder is generting C code; it seems to me that although the generated C code is compiling and executing without problem (in general case), this code is far from being optimized.
Hereunder is an example of a piece of code which can be obtained:
int8_T fIn1[32768];
creal32_T c[32768];
int32_T i;
memset(&fIn1[0], 1, 32768U * sizeof(int8_T));
for (i = 0; i < 32768; i++) {
if (fIn1[i] == 0) {
c[i].re = 0.0F;
c[i].im = 0.0F;
} else {
ci[i].re = 0.0F;
c[i].im = 0.0027777777785F;
}
}
I guess that if this code was coded by a human developer, he will be fired immediately ! fIn1[I] is always equal to 1 and can never be equal to 0 thus if condition is useless.
How can I trust a tool which can produce such a weird code ? Should I read all the generated code to optimize it manually ?
Or someone is able to explain me why Embedded Coder is inserting if condition in this case ?
Best regards.
  1 Comment
Walter Roberson
Walter Roberson on 12 Aug 2020
Does the code produce incorrect answers? If not, then you have no reason not to trust it to produce correct answers.
If what you happen to need is to trust that it will produce the most efficient possible code, then that is a different issue. Any tool that generates code for a different language must trust that the compiler optimizes well. It is not appropriate for a mechanical code generation tool to get into details such as variable lifetime analysis, because people who use the generated code have different requirements at different times. Tools such as Embedded Coder should not have a lot of knowledge about a lot of different toolchains and their optimization engines such that Embedded Coder should be using techniques such as deliberately inserting junk code in order to force a toolchain to react a particular way so that Embedded Coder would reach a particular goal.
If you need very high efficiency in the generated code, then you should be reading all of the machine language dumps of your toolchain's output.

Sign in to comment.


Didier Billard
Didier Billard on 17 Aug 2020
Hello dear Walter,
Thank you for your question.
To give you more information about the generate code, please find hereunder my comments:
  • first the generated code seems to produce the correct answer but time consumption to obtain the answer is out of specification. This means that generated code cannot be accepted today and this may be due to the fact that the generated code is checking 32768 times a condition which happens very very rarely. And AFAIK, this condition is totately useless as the same result will be obtained without it.
  • second we cannot rely on some hypotetical optimization by compiler. Our customer is requiring that all the lines of generated code are covered which is not the case as condition is never reached. And we cannot tell our customer something like "Oh don't worry, the compiler will remove these lines in this critical section of the control system of our nuclear power plant..."
  • third the example I give is not realisitc; in fact, the input signal is not a constant vector but we know that the probability for a value to be 0 is very very rare not to write impossible. For sure the compiler does not know that and it will not be able to remove the uncovered lines by tiself.
We just would like Embedded Coder not to generated these uneccesary lines (i.e. the if condition) so that time comsumption is acceptable and coverage is ok; but up to now we don't know if is possible.
best regards.

Products


Release

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!