bloated code

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All,
I am stumped by some code where a straightforward statement causes instant bloating of my code.

Scenario
Case 1
I am using an ATmega8. Compiler option -Os. My code is sitting at approx 4.2K and then I add the statement

#define _6ML	 52.000/0.025
#define _6MH 	 54.000/0.025
uint16_t channel;
   if((channel>=_6ML)&&(channel<_6MH))
      TX_INHIBIT=0;
          else
      TX_INHIBIT=1;

This causes the code to goto to about 6.8 K.
When I look at the hex output it appears to add at the top of the code an array of binary numbers 00,01,01,02,02,02,02,02,(8x03),(16x04),(32x,05),(64x06), etc where the number of numbers increase exponentially, which the dis-assembler treats as non-sense.

This of course does not happen when I do it in a test program. Currently I have the code patched out to enable me to proceed!

Case 2.
In the same code I want to add a 2X16 LCD, so I added the lcd functionality from the WinAVR examples and presto, instant bloat code to exceed toe 8K limit.

When I investigate this, I find by patching out a code] _delay_us(40);[/code] in the HD7780 code
and then I come back to about 4.6K

I use _delay_ms(), elsewhere in one of my modules and it seems to behave OK.

I was not able to find out what the bloat code looks like as no binary is generated.

The remaining code generated so far works OK in the target system(without the comparison & LCD of course). Has anyone come accross this bloating problem, who may be able to throw some light on it.

(I gather one of Murphy, Darwin or Lord Thompson has finaly got me!)

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

Last Edited: Sun. Nov 29, 2009 - 11:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I believe something like including libm.a and libprintf_flt.a may help, at least that's what I was told to do. :?

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I add your code to a non-float project of mine it adds about 1768 bytes. This is because the compiler invokes floating point routines to compute _6ML and _6MH. The following eliminates the need for the floating point code to be linked in:

#define _6ML    (int)(52.000/0.025)
#define _6MH     (int)(54.000/0.025)

You might want to cast to unsigned or whatever.

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks guys.
I have documented my findings so that this may help someone in the future.

My initial code had bloated from 4810 to 6860 words
before making any changes. Incidentily, the bloated code did work OK.

1. I tried John suggestion first.
Including libm.a caused my code to go from 4810 words to 4910 words.
Re-enabling my compare code caused code to go to
5296. So that certainly gives a big improvement ( but more then what I thought, as I reckon I could do this in assembler (whilst not easier) with less words).

2. Including libprintf_flt.a did nothing for me. I tried it second as I am not doing any printf & my numbers are integers.

3. I tried cpluscon suggestion next and, whilst I though it looked like the right answer, it had no effect as it gave me 5860 words. I does strike me that, as the expression is evaluated at compile time, that it should not cause floating point libraies to be linked into my target code (but I am no expert at compilers theory).

4. At this stage I re-enabled the _delay_us(40) and it increased the code from 5296 to 6184 , which is rediculous(?). Including libprintf_flt.a did not improve that.

Summary.
Thanks John, your suggestion was good!
Still looking for answer on the _delay_us() bloat, but perhaps it is normal. I will try & determine how much code _delay_ms() which I use elsewhere contributes to the code.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I does strike me that, as the expression is evaluated at compile time, that it should not cause floating point libraies to be linked into my target code
My guess is that the compiler is required to promote the integer to floating point but that is a guess. In any case, with -Os my installation emitted floating point calls for 52.000/0.025 and casting to int eliminated them. I have avr-gcc (WinAVR 20090313) 4.3.2.

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would try out to define

#define _6ML    1
#define _6MH    1

and then compile to see if that is really causing the bloating. Namely, the typecast to integer SHOULD have removed the addition of floating point library which seems to be the reason for bloating.

Look after expressions like 10/2 - those are interpreted as floting point numbers although thy seem not to be so. Any non-typecasted division usually results in floating point library to be involved.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks eskoilola and cpluscon,
I did a little more research on this, as I reckon that your suggestion should have applied.
So I found one define in an include, that I had not modified with a cast. As soon as I had done that,
it now no longer bloats, without requiring the libm.a
include. In fact a pleasant little bonus, the code has now gone down to 4472 from 4910.

Thanks all!

Still have the problem with the _delay_us() call
when it is patched out it generates
Program: 4960 bytes (60.5% Full)
& when enabled exceeds 8K limit by some 300 words??

Program: 8534 bytes (104.2% Full)

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

LDEVRIES wrote:

Still have the problem with the _delay_us() call
when it is patched out it generates
Program: 4960 bytes (60.5% Full)
& when enabled exceeds 8K limit by some 300 words??

Program: 8534 bytes (104.2% Full)

The only time I've seen the _delay_xx() stuff blow up code was when the argument passed to it was not a constant, which doesn't work correctly anyway.

--- bill

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Bill, I think you just pinned my problem down.
Come to think of it there was a recent thread on this but , it did not turn up on my research.

Thanks to all. QED

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just don't understand why you'd want to use a floating point constant for this anyway. When the pre-processor has been applied your code is:

   if((channel>=52.000/0.025)&&(channel<54.000/0.025))

The comparisons force 'channel' to be promoted to float and hence the inclusion of the floating point lib.

Now I don't know about your Casio but my one says that 0.025 divides into 52.0 two thousand and eighty times and it divides into 54.0 two thousand one hundred and sixty times. So why not just:

   if((channel>=2080)&&(channel<2160))

and if you want to macro-ise this:

#define _6ML    2080 // 52.000/0.025 
#define _6MH    2160 // 54.000/0.025 

(or go with 'cpluscon's typecast in the macro but be careful not to switch the optimiser off in that case)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Cliff,
I actually had that implemented earlier, but changed it to make it more readable. and self documenting. As you can probably gather this is all to do with frequency synthesizer for 52-54 Mhz. with 25Khz. channels. (in addition to many other bands)
As this code will handle many many frequencies, I thought it would make the code more readable to have channel frequencies, band limits direct, repeater off sets, IF frequencies & reference dividers and the channelling in Mhz. so as to avoid seperate calculation (potentially thousands) Ie. let the compiler do the calculation. I wasn't sure whether it would work , but when the synthesizer sprang into life I was happy with the result. But I had not counted on the inadvertant code bloat! Another lesson learnt!

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You should also always - as in _always_ - parenthesize macros expressions, otherwise you can end up with completely random results due to the operator precedence rules.

A good trick with gcc is to generate the disassembly inlined with the corresponding C code line (check avr-objdump --help), this will show you what code is generated for what simple-looking C expression, and what "magic" libraries get linked too.

Author of simavr - Follow me on twitter : @buserror

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

buserror wrote:
You should also always - as in _always_ - parenthesize macros expressions, otherwise you can end up with completely random results due to the operator precedence rules.

A good trick with gcc is to generate the disassembly inlined with the corresponding C code line (check avr-objdump --help), this will show you what code is generated for what simple-looking C expression, and what "magic" libraries get linked too.

That's what makes developing in C so much easier than plodding around in assembler. With C, you take a guess as to how to express the computation you want, then let the compiler do the grunt work for you. Then you examine what assembler instruction sequence it decided to generate, and compare it to the one you would want (it helps at this point if you go ahead and generate the assembler sequence yourself, just for educational purposes). Then, you try and guess how you might adjust the C source code (add parentheses, rearrange terms, cache an intermediate value, do some casting, genuflect in the direction of Bell Labs, etc.) to make the compiler do as you'd like. Then you recompile that, and repeat until the result is satisfactory. Simple. Whereas with assembler, you're forced to do everything yourself, and write a sequence of instructions that does what you want.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gcc does a lot of very, very clever little tricks. Yes, it adds bloat if you go overboard, because it's /designed/ to "make it work" but if you are aware of the underlying architecture, you are a winner when you get a C compiler.

It's true for /any/ architecture. /Knowing/ the assembly is a huge boost of productivity, performance and quality when writing C -- /Writing/ Assembly is a huge waste of time and headache for maintenance (not even mentioning architecture change)

C was invented on architectures that were barely any bigger than an AVR after all!

Author of simavr - Follow me on twitter : @buserror