Programme Doesn't Work after Optimization - What to look for?

Thread Starter

TechWise

Joined Aug 24, 2018
151
Slightly vague question I know... I have written quite a long control algorithm in C for an embedded processor. The default build setting is zero optimization, and that is what I have been using up until now. The programme works perfectly as far as I can tell. I get no compiler errors or warnings. I have also compiled parts of the algorithm in CodeBlocks using the gcc compiler with the "wall" of warnings enabled and I get no warnings at all. Today, I cranked up the optimization options to allow a faster sampling frequency. However, the code no longer works as intended. It doesn't crash, it's just some of the outputs are not as expected.

What sorts of problems are associated with optimized code that may be hidden during an un-optimized build? Any variables that are accessed by ISRs are declared as volatile as I was concerned that they may be getting optimized away but that doens't seem to be the issue. I've read that optimized code may pack arrays closer together so if you accidentaly increment a pointer too much it can cause an issue. I doubt that the mathematics of my algorithm would work at all if that were the case. What else should I be looking for?
 

nsaspook

Joined Aug 27, 2009
8,262
Too little information. Multi-threaded, multi-processor?

Usually the compiler will rearrange/reorder code sequences, memory sequences, logical inferences, variable lifetimes, etc... to optimize space and/or run-times. For example: If you make assumptions (programmer errors) about read/write sequences with things like interrupts with cached multi-core systems, volatile won't help the compiler do the right thing without memory barriers to sequence correctly.
https://my.eng.utah.edu/~cs5785/slides-f10/Dangerous+Optimizations.pdf
http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.06.07c.pdf
 

Thread Starter

TechWise

Joined Aug 24, 2018
151
Too little information. Multi-threaded, multi-processor?

Usually the compiler will rearrange/reorder code sequences, memory sequences, logical inferences, variable lifetimes, etc... to optimize space and/or run-times. For example: If you make assumptions (programmer errors) about read/write sequences with things like interrupts with cached multi-core systems, volatile won't help the compiler do the right thing without memory barriers to sequence correctly.
https://my.eng.utah.edu/~cs5785/slides-f10/Dangerous+Optimizations.pdf
http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.06.07c.pdf
Thanks for the links. I'll take a look.

It is a dual core TMS320F28379D, but I am only using one core. I am using the PWM module to generate an interrupt. Inside that interrupt, I set a flag. That flag is polled in an infinite loop within main(). If the flag is set, my algorithm gets called, then the flag is cleared. There should be nothing else that could interrupt the flow of the program or modify a variable outside of the control algorithm itself.
 

nsaspook

Joined Aug 27, 2009
8,262
Is the PWM interrupt actually triggered? This is where a gpio debug pin set high/low/toggle is useful to trace code execution.
 

Papabravo

Joined Feb 24, 2006
15,761
Thanks for the links. I'll take a look.

It is a dual core TMS320F28379D, but I am only using one core. I am using the PWM module to generate an interrupt. Inside that interrupt, I set a flag. That flag is polled in an infinite loop within main(). If the flag is set, my algorithm gets called, then the flag is cleared. There should be nothing else that could interrupt the flow of the program or modify a variable outside of the control algorithm itself.
If the optimizer is unaware of the relationship between the flag and the interrupt it might optimize it away because it is unable to discover that the flag is modified in any place that it can see. Look up the use of the "volatile" keyword.

https://www.geeksforgeeks.org/understanding-volatile-qualifier-in-c/
 

Thread Starter

TechWise

Joined Aug 24, 2018
151
Is the PWM interrupt actually triggered? This is where a gpio debug pin set high/low/toggle is useful to trace code execution.
The interrupt is definitely triggered and the control algorithm definitely gets called. The behaviour is perfect until I start trying to optimize for speed. Previously, I set breakpoints and ran the controller for 10 iterations. After each iteration, I verified that every variable in the controller had the value it should by crosschecking with a MATLAB implementation of the same controller.
 

Thread Starter

TechWise

Joined Aug 24, 2018
151
If the optimizer is unaware of the relationship between the flag and the interrupt it might optimize it away because it is unable to discover that the flag is modified in any place that it can see. Look up the use of the "volatile" keyword.

https://www.geeksforgeeks.org/understanding-volatile-qualifier-in-c/
The flag was declared as a "volatile int" for this very reason. The flag definitely gets set and the control algorithm definitely gets called. One of the first things to happen inside the control algorithm is that it copies it's inputs directly to a DAC register, so that I can verify on a scope that the function is at least called. It is definitely called, it's what happens next that's causing the issue.
 

nsaspook

Joined Aug 27, 2009
8,262
So what exactly is not working? A calculation has wrong results and/or functions are not being called, device registers (like a DAC) not being read or written in the right sequence or order?
Bet sure Code-prefetch mechanisms and data cache are disabled as a correctness test.
 

Thread Starter

TechWise

Joined Aug 24, 2018
151
So what exactly is not working? A calculation has wrong results and/or functions are not being called, device registers (like a DAC) not being read or written in the right sequence or order?
Bet sure Code-prefetch mechanisms and data cache are disabled as a correctness test.
The controller takes in voltage and current measurements then calculates a duty factor for the PWM module. The voltages and currents being read in are correct because I can output them to the DAC to check. The duty factor coming out the other end is wrong because the resulting current is far too large.

Something is going wrong in the calculations between the latest values being read in and the new duty factor being output. Those calculations comprise a lot of matrix math, where each element of the matrices is a complex number. Every "matrix" is in fact a 1D array of pointers to 1D arrays of pointers to structs containing a real and imaginary component. As you can imagine, there are a lot of pointers on the go and quite a lot of potential to increment a pointer too far and cause havoc. Yet, it works until the optimization is cranked up which is the part I'm struggling a bit to figure out. I would have thought that an error in the pointer arithmetic would cripple the whole thing even without optimization.

In any event, I think the best way forward will be to move my dac_output() function further and further down the control algorithm until I localise where the output values diverge from what I'm expecting. I had posted here in case there were any "classic" issues that arise specifically when seemingly correct code is optimized.
 

nsaspook

Joined Aug 27, 2009
8,262
The controller takes in voltage and current measurements then calculates a duty factor for the PWM module. The voltages and currents being read in are correct because I can output them to the DAC to check. The duty factor coming out the other end is wrong because the resulting current is far too large.

Something is going wrong in the calculations between the latest values being read in and the new duty factor being output. Those calculations comprise a lot of matrix math, where each element of the matrices is a complex number. Every "matrix" is in fact a 1D array of pointers to 1D arrays of pointers to structs containing a real and imaginary component. As you can imagine, there are a lot of pointers on the go and quite a lot of potential to increment a pointer too far and cause havoc. Yet, it works until the optimization is cranked up which is the part I'm struggling a bit to figure out. I would have thought that an error in the pointer arithmetic would cripple the whole thing even without optimization.

In any event, I think the best way forward will be to move my dac_output() function further and further down the control algorithm until I localise where the output values diverge from what I'm expecting. I had posted here in case there were any "classic" issues that arise specifically when seemingly correct code is optimized.

Good luck, that sounds like FOC Space vector modulation code.
 
Top