optimization problem

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

optimization problem

1,725 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by markr on Wed Oct 30 13:13:20 MST 2013
I've run into a problem that I believe is a compiler optimization problem. I'm using an LPC-812 on a breakout board that does not support either JTAG or SWD, so debugging this has been interesting. I'm using LPCXpresso v6.0.2 Build 151 2013-09-18. The code in question is:

...set-up a bunch of things, including clocks, ISR handles, pins etc, then...
while (1)                                /* Loop forever */
  {
  while(!LPC_GPIO_PORT->W0[ISP_PIN]) ; // wait on ISP button press
  while (TimeTick <= change_pwm); //wait for the counter to advance
  TimeTick=0;
#ifdef DBG_OUTPUT
  printf("R=%3d, G=%3d, B=%3d\n\r",red_pwm,green_pwm,blue_pwm);
#endif
  NOTPORT0(PORT0_BIT6); // toggle pin
//  printf("%2d",color);
  switch (color) {
... several cases: with breaks, a default, then end of the while(1).


All code from the switch() on-wards does not appear to be getting executed. The switch has several cases, each case has several tests and modifies global variables that are used in ISRs. The end of the switch is the end of the while(1).

If either printf() shown above is enabled (either enable the #ifdef or remove the comment), the switch operates correctly. If neither one is present, the code in the switch is never executed. If a printf() is placed in _any_ of the case statements, the switch executes and all cases operate correctly.

I know the processor is not off in the weeds because:
- There are pin toggles in 2 timer ISRs that keep toggling.
- The NOTPORT0 toggles a pin and that pin toggles correctly, so the primary while loop appears to be functioning correctly.
- The pin toggled by the NOTPORT0 stops toggling when the ISP button is pressed (as would be expected) and the ISRs keep running (as also expected and evidenced by pin toggles). And the pin controlled by the NOTPORT0 resumes toggling when the button is released (again as expected.)

Everything else appears to be operating correctly, just the entire switch structure is never executed! I chased this for most of a day (debugging w/o a debugger is fun!) until I started changing the optimization.

The project was initially set with size optimization (-Os) I changed to none (-O0), cleaned and rebuilt and it worked. Change it back to size (-Os), clean and rebuild and it doesn't work. There is definitely something bad going on with optimization. (I haven't tried the other levels yet.)

Besides the problem noted above, it appears that just changing the optimization level does not cause a re-build of the project. The code remains working or not working, irrespective of the optimization setting. Only if I change the optimization _and_ touch the code (add/delete a space and save) and recompile, does the behavior change. A clean and rebuilt does generate new code and will cause it to work or not work, depending on the state of the code and optimization.

The need to clean and rebuilt when changing optimization is not that surprising and is a minor nuisance. But having optimization remove most of main() is another issue.

I'm new to LPCXpresso and ARM in general, but have been using other micro-controlllers and IDEs for years. I'll admit I don't know LPCXpresso well enough to generate assembly and look at the resulting intermediate code. (It took some wrangling to get it to output a hex file for Flash Magic.)

Any thoughts or suggestions would be appreciated.

-markr
Labels (1)
0 Kudos
14 Replies

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Thu Dec 12 11:11:49 MST 2013
In general O2 is the better (=faster) choice. If you are short of flash, use Os (= LPCXpresso default release setting).
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Thu Dec 12 10:57:24 MST 2013
You can use -O2 or -Os - it is your choice.

Provided you obey the rules (as described in the FAQ that I provided a link to) there will be no issues due to optimization.

Read the Help (Help->Help contents) for information on all of the optimzations available and which ones are used at each level. Beware: this is for very advanced users only.
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by LabRat on Thu Dec 12 10:55:42 MST 2013

Quote: Duraimurugan
Is it recommended to use ...



It is recommended to use Google:

http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Dore on Thu Dec 12 09:59:56 MST 2013
Is it recommended to use -Os or -O2 (in release mode)? will  there be any issues due to this which can affect the actual functionality?
And also if I would like to make the optimization on my own equivalent to the one on O2 or Os setting, how I can move forward on this?
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rocketdawg on Thu Dec 12 09:01:22 MST 2013
consider an accessor function to get the variable "color"


uint32_t color;
uint32_t GetColor(void)
{
   return color;
}

switch(getColor()) { blah blah}

"volatile" may or may not work, (depends on the compiler)  but the compiler cannot optimize out a function call.
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Thu Dec 12 08:28:27 MST 2013
First of all, if you are worried about the size of your code, DO NOT use -O3 as it will increase code size (compared with -Os or -O2). This is because -O3 optimization is to do with speed and not size. For example, it will unroll small loops, making the code run faster, but at the cost of increasing the size.

Therefore, I suggest you use -O2 or -Os.

Also, please read this FAQ:
http://support.code-red-tech.com/CodeRedWiki/CompilerOptimization
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Dore on Thu Dec 12 02:00:13 MST 2013
Hi,

I am running short of memory in my controller. So I have enabled the optimization level 3 (Release mode) in my LPCXpresso. I am using LPC1114FHI33/302. With this one my code is fitting into the memory. But I will have to look into few concerns.

- Is there any special care i have to takecare since I am enabling the optimization?
- Is ok to keep the compiler optimization technique?
- Any inputs on what exactly the optimization does and is it possible for me to take care of them so that I can go without any optimization?

Regards,
Duraimurugan
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wmues on Thu Oct 31 00:52:12 MST 2013
Markr,

if color is used only inside main(), there is no need to make color volatile.

But you have 2 while loops at the start of the loop.
- is TimeTick volatile?
- Is LPC_GPIO_PORT->W0[ISP_PIN] volatile?

If not, the compiler might assume that one of those variables is 0 and not changing value, so the rest of the loop is optimized away (unreachable code).

regards
Wolfgang
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Wed Oct 30 20:28:46 MST 2013
I would suggest that you need to debug this. You said that 'it appears the switch statement is not being executed' but you don't actually know until you debug it. I would suggest
- in the Release build add the -g3 flag (Maximum debug info)
- disassemble your application so you can see what the code is
- single step through your code to find out what is really not working.
It is not easy debugging optimized code (all of the reasons explained the the FAQ you have been pointed at) but you will need to do it. These GCC compilers are very mature, so it is very unlikely to be a compiler problem.

We can speculate until the cows come home, but that is all we can do - speculate.

Regarding use of volatile - the compiler is doing what every other ARM compiler will do when optimizing. It is very very different to the 8/16 bit compilers.
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by markr on Wed Oct 30 19:42:07 MST 2013
The code mentioned above is below.

-markr

while (1)                                /* Loop forever */
  {
  while(!LPC_GPIO_PORT->W0[ISP_PIN]) ;// wait if ISP button pressed
  while (!TimeTick);
  TimeTick=0;
#ifdef DBG_OUTPUT
  printf("R=%3d, G=%3d, B=%3d\n\r",red_pwm,green_pwm,blue_pwm);
#endif
//  NOTPORT0(PORT0_BIT6);
//  printf("%2d",color);
  switch (color) {
  case 0: //red
  if (inc_dec) {
   if (++red_pwm >= MAX_PWM) inc_dec = FALSE;
   }
   else if (--red_pwm == 0) {
   color++;
   inc_dec = TRUE;
   }
   break;
  case 1: //green
  if (inc_dec) {
  if (++green_pwm >= MAX_PWM) inc_dec = FALSE;
  }
  else if (--green_pwm == 0) {
  color++;
  inc_dec = TRUE;
  }
  break;
  case 2:// blue
  if (inc_dec) {
  if (++blue_pwm >= MAX_PWM) inc_dec = FALSE;
  }
  else if (--blue_pwm == 0) {
  color++;
  inc_dec = TRUE;
  }
  break;
  case 3:// purple
  if (inc_dec) {
blue_pwm++;
red_pwm++;
  if (blue_pwm >= MAX_PWM) inc_dec = FALSE;
  }
  else {
blue_pwm--;
red_pwm--;
  if (blue_pwm == 0) {
  color++;
  inc_dec = TRUE;
  }
  }
  break;
  case 4:// yellow?
  if (inc_dec) {
green_pwm++;
red_pwm++;
  if (green_pwm >= MAX_PWM) inc_dec = FALSE;
  }
  else {
green_pwm--;
red_pwm--;
  if (green_pwm == 0) {
  color++;
  inc_dec = TRUE;
  }
  }
  break;
  case 5:// orange? blue is too weak
  if (inc_dec) {
green_pwm++;
blue_pwm++;
  if (green_pwm >= MAX_PWM) inc_dec = FALSE;
  }
  else {
green_pwm--;
blue_pwm--;
  if (green_pwm == 0) {
  color++;
  inc_dec = TRUE;
  }
  }
  break;
  case 6:// white
  if (inc_dec) {
red_pwm++;
green_pwm++;
blue_pwm++;
  if (green_pwm >= MAX_PWM) inc_dec = FALSE;
  }
  else {
red_pwm--;
green_pwm--;
blue_pwm--;
  if (green_pwm == 0) {
  color++;
  inc_dec = TRUE;
  }
  }
  break;
  default:// clean up (should not be necessary)
  color = 0;
  inc_dec = TRUE;
  red_pwm=0;
  green_pwm=0;
  blue_pwm=0;
  }
}

0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by markr on Wed Oct 30 19:40:50 MST 2013

Quote: R2D2

I would  ;-)
http://www.support.code-red-tech.com/CodeRedWiki/CompilerOptimization?highlight=%28volatile%29



Looking at the link, all I can say is wow. I've used CCS for TI, GCC for Atmel and MicroChip and IAR for all 3 and never seen anything like this. Sure, the usual problems were a while loop that increments a dummy variable vanishes, or occasionally a repeated increment to a memory mapped I/O may disappear when optimization is turned up. But nothing like this.

Unfortunately, marking color volatile didn't fix the problem. Same behavior. And there were already variables inside the switch that were marked volatile. The only thing that fixes this is turning off _all_ optimization. Even -O1 fails. I'll retry this tomorrow on another vendor's compiler with the same code and see what happens.

I've included the entire switch code below:
- The variables "red_pwm", "blue_pwm" & "green_pwm" were already volatile.
- Adding a pin I/O inside the switch and/or cases didn't help.
- Making color volatile didn't help.
It only works correctly is optimization is turned off completely.

This leads to another question: How to mark I/O as volatile when all the register structures are already defined in library includes? Especially on a processor like ARM where _all_ I/O is memory mapped?

For example, I'm using a macro to access the I/O ports:
(I give up, the forum editor eats the example. Its a define using the standard LPC I-O structure)
If the problem is memory mapped I/O, shouldn't _all_ I/O be marked as volatile in the libraries? (hint: it's not)

Any other ideas? This isn't the end of the world, I'm just trying to educate myself on ARM in general and NXP in particular. The LPC8xx looked like a good option for high performance in a small package and low price. It would be nice to use the "house brand" compiler, but problems like this are annoying. I'm glad this isn't a memory limited project on a deadline....

-markr

0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Wed Oct 30 15:11:03 MST 2013

Quote: markr
I wouldn't expect an optimizer would discard an entire switch structure...



I would  ;-)

http://www.support.code-red-tech.com/CodeRedWiki/CompilerOptimization?highlight=%28volatile%29
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by markr on Wed Oct 30 14:57:01 MST 2013

Quote: R2D2
Is 'color' volatile?



no. it's an unsigned int only used in main. It's basically the "state" of the system: its incremented in every case statement, so the next pass around the while loop goes to the next state/switch-case.

You're onto an interesting idea. I'll try changing it.

I wouldn't expect an optimizer would discard an entire switch structure just because the switch state is only modified inside the switch. Makes state machines hard to implement in SW. :-)

-markr
0 Kudos

1,565 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Wed Oct 30 14:12:35 MST 2013
Is 'color' volatile?
0 Kudos