This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

optimisation settings causing odd behaviour

Hi,

I've recently been experiencing some concern regarding the behaviour of a program, for which the optimiser, when set to favour size [OPTIMIZE (6, SIZE)], occasionally leads to the contents of a global variable getting trashed/overwritten. If the optimisation settings are altered to favour speed, this no longer happens.

It appears not to be an issue with specific XDATA address (where the variable resides), since changing the variables location doesn't prevent this from happening.

The variable in question is only ever modified via a single increment within a timer interrupt function.

Has anyone else experienced anything like this?

IDE: uV2
Compiler: V6.23a
Link/Loc: V4.23

Thanks for any illumination...

David

Parents
  • <Calling functions from the main thread and from an ISR is potentially very dangerous.>

    Yes, I know. ;-) An example of a function called from the main thread and an ISR is a circular-buffer function. The main thread writes to the buffer, and the ISR reads from it (or vice versa). Thus the main thread (or an ISR) calls both the read- and write-buffer function.

    <How did you discover that a variable was getting changed by the ISR? Were you looking with the simulator for example? Does the function actually work OK?>

    Yes. Yes. With optimisation set to level 1, all works as expected.

    <If you want everything to use just one register bank then you should never use the "using" keyword.>

    Yes, I discovered this the hard way! Thanks anyway for the tip. :-)

    Are there any lists of 'general' problems that can occur with optimisation, and how they can best be avoided?

    Steve Merrick
    Software Designer
    Tribal Data Solutions

Reply
  • <Calling functions from the main thread and from an ISR is potentially very dangerous.>

    Yes, I know. ;-) An example of a function called from the main thread and an ISR is a circular-buffer function. The main thread writes to the buffer, and the ISR reads from it (or vice versa). Thus the main thread (or an ISR) calls both the read- and write-buffer function.

    <How did you discover that a variable was getting changed by the ISR? Were you looking with the simulator for example? Does the function actually work OK?>

    Yes. Yes. With optimisation set to level 1, all works as expected.

    <If you want everything to use just one register bank then you should never use the "using" keyword.>

    Yes, I discovered this the hard way! Thanks anyway for the tip. :-)

    Are there any lists of 'general' problems that can occur with optimisation, and how they can best be avoided?

    Steve Merrick
    Software Designer
    Tribal Data Solutions

Children
  • Do you receive ANY warnings from the compiler or linker?

    Jon

  • one register set - set 0 - for the main thread and for ISRs
    Which will guarantee erratic behaviour. The reason you see it more/only in some cases is purely due to timing which should be irrelevant to your code.

    Erik

  • I once had a problem that only showed in 'release' builds (that is, running from flash.) It didn't show during debugging (running from RAM.) It turned out to be an overlooked interaction via a flag between an ISR and the main thread (or threads, since RTX166 Tiny was involved as well.) Most likely the reason why it didn't show in debugging was that execution speed was different, so the events that lead to the problem didn't happen simultaneously.
    I found the mistake in the program just looking at the suspicious piece of source code for a while. Swapping a couple of lines and disabling interrupts in the right place solved the problem.
    If you have reasons to believe that your problems come from interaction between an ISR and the main thread, try analysing the source code, paying attention to variables that are modified both by the ISR and the main thread. The problem only gets worse in a multitasking environment. Disabling interrupts to protect atomic operations solves the problem. Identifying atomic operations is the hard part.

    - mike

  • Jon: I receive no compiler or linker errors or warnings.

    Erik: Please can you explain how "one register set ... will guarantee erratic behaviour."? It will certainly be less efficient, but if the context is saved and restored correctly, the use of a single register set should not introduce a risk of any sort, as I understand it. What am I missing, please?

    Steve Merrick
    Software Designer
    Tribal Data Solutions

  • Reducing my problem to general terms, it would appear that the optimiser is sharing memory (for local variables) between functions, and sometimes this is inappropriate.

    Is there a directive (e.g. NOAREGS, and so on) that will tell the compiler that 'this function's local variable memory should not be overlaid'? I can't find one....

    Steve Merrick
    Software Designer
    Tribal Data Solutions

  • I think that declaring the function as reentrant will work, but you need take a look at the manual as the exercise is costly in terms of memory usage and speed.

    Stefan

  • Yes, Stefan, 'reentrant' probably does more than I need - but I think it may be my only option. I'm currently going through my code, making all functions called from ISRs reentrant; there are a few that aren't, and this could definitely lead to the problems I've noted.

    Watch this space.... ;-)

    Steve Merrick
    Software Designer
    Tribal Data Solutions

  • If you have functions that are called by the main program and by an interrupt, the linker will generate a warning (unless they were disabled). Typically, the warning will be a multiple call to segment.

    The linker generates a call tree and has to put the isr-main function somewhere in the tree.

    Since the isr-main function is called by the main program, it probably is stored in that tree. If other functions are also called by the function that calls isr-main, the memory of isr-main is overlayed.

    If an ISR subsequently calls the isr-main function, the memory used by isr-main is corrupted.

    This probably appears as variables/arguments in other aparently non-related functions getting corrupted.

    If this is the problem you are having, the following knowledgebase article describes exactly what to do: http://www.keil.com/support/docs/2042.htm.

    Jon

  • Excellent! Thanks, Jon, that was what I was after.

    Sadly, in the way of things in the real world, I can't get the original version to fail now, but I'll be patient, and I'll get there.

    As it stands now, ALL functions called from ISRs are marked 'reentrant', and I think this will cure my problem. But not all of them need to be reentrant; some of them only need be excluded from overlaying to cure the problem. [They are only called by one ISR, and never from the main thread.]

    Thanks everyone for your help!

    Steve Merrick
    Software Designer
    Tribal Data Systems