Go Down

Topic: reducing sketch size (Read 1 time) previous topic - next topic

roypardi

Hi,


using the NG ATmega8 so I only have 7k to work with and am wondering where I can save some space.


--do the length of variable names add to file size or do those get tokenized so it doesn't matter?

--do many small functions (compared to a larger one that uses states) affect file size?


can't think of anything else that might save size, so I thought I would ask.

--Roy

MikMo

The length of names should not make any difference in the compiled code.

I think that many small functions may take up more space, but you just have to make a test, it really depends on how your program is written.

You can actually upgrade your board to use the 168 processor and double the available memory. You can buy a 168 with the bootloader pre burned for 5$. I am planning on doing that with my two NG boards.

mem

Hi Roy,

I would doubt that having one big function would be an effective way to reduce program size, even if it did save a few bytes. The complexity of coding everything in a single function could make your code difficult to debug and maintain.

I have found the biggest factor in code size is the libraries that are used with a sketch. For example, using fixed point rather then floating can make a big difference, just adding a single floating point variable can add 500 bytes to a sketch size.  

Surprisingly, you can often reduce your overall code size by adding a little code yourself that eliminates the need to link an external library.

roypardi

tx for the replies-


I didn't know I could upgrade the chip - that seems totally worth it. I noticed that using Libs add a lot to the size- but wasn't aware that different data types do as well.


I haven't maxed out the memory yet but I thought I would try to learn some "best practices" as I am roughing this sketch out so I don't have to go through and do major changes.


--Roy


westfw

First of all, 7K is a pretty substantial amount of space for a compiled program (not to be confused with source code size.)

Secondly, it's generally a bad idea to make your program obscure just to save memory, especially with the bigger CPU chip out there as a possibility (and and even bigger chip "real soon now." (maybe.)

All that said, in some rough experiments, one good way to save space is to avoid using variables that are larger than they need to be.  (don't use "int" when "char" would do, don't use "long" when "int" or "char" would do.)  Not only do larger variables use up RAM, but they require more code to do operations on, even if that's just passing them as arguments to subroutines.
For instance, if you call "delay(1000);" more than just a couple of times in your program, you can save program memory by writing
a delay_onesec() function:
Code: [Select]
void delay_onesec(void)
{
 delay(1000);
}

Just because of the code overhead of passing that long argument (1000) to delay each time.

roypardi

thanks! this is the kind of info I am interested in.

In your delay example - having it as a function with a predefined val gets compiled differently than just calling 'delay(1000)'? I assume there would be the same overhead as delay(int) if you were passing the int as a parm to your function? (i.e. it's not a prefined val so no optimization is possible). Is that correct?

None of this is critical to what I am writing now - but I am trying to get 'more with the program' of using c compared to lingo/actionscript.


--Roy

westfw

delay() takes a long (4 bytes) as it's argument ) (which makes sense, since with an int the maximum delay time would only be about one minute), so each call to delay() will need to pass four bytes of arguments.  If you disassemble the BLINK sketch, for example, you'll see that loop looks like this:

Code: [Select]
void loop()                     // run over and over again
{
 digitalWrite(ledPin, HIGH);   // sets the LED on
 fa:   61 e0           ldi     r22, 0x01       ; 1
 fc:   80 91 00 01     lds     r24, 0x0100
100:   0e 94 bc 01     call    0x378 <digitalWrite>
 delay(1000);                  // waits for a second
104:   68 ee           ldi     r22, 0xE8       ; 232
106:   73 e0           ldi     r23, 0x03       ; 3
108:   80 e0           ldi     r24, 0x00       ; 0
10a:   90 e0           ldi     r25, 0x00       ; 0
10c:   0e 94 dc 00     call    0x1b8 <delay>
 digitalWrite(ledPin, LOW);    // sets the LED off
110:   60 e0           ldi     r22, 0x00       ; 0
112:   80 91 00 01     lds     r24, 0x0100
116:   0e 94 bc 01     call    0x378 <digitalWrite>
 delay(1000);                  // waits for a second
11a:   68 ee           ldi     r22, 0xE8       ; 232
11c:   73 e0           ldi     r23, 0x03       ; 3
11e:   80 e0           ldi     r24, 0x00       ; 0
120:   90 e0           ldi     r25, 0x00       ; 0
122:   0e 94 dc 00     call    0x1b8 <delay>
126:   08 95           ret
}

Each call to delay(1000) ends up taking 5 instructions (12 bytes since the call is 4 bytes long.)   The call to the hypothetical delay_onesec() is only 1 instruction (4 bytes) and delay_onesec() itself is only 14 bytes long, so you break even pretty quickly.  (The number of instructions in the execution path is somewhat longer, but you share that path among several callers, so the total number of bytes of code is less.  And the extra few instructions are irrelevant when you're delaying for a second anyway.)  Even the BLINK example gets shorter (by a whole two bytes) using a new delay_onesec() function instead of the two existing calls to delay(1000);

Cheater

I've got a annoying tendency to do strange things to make my programs small and efficent. :)

If your program is 7.5k and you have 7k then you can very easily shrink it down.
Depending on your coding style and what your doing you could possibly get 8 - 9k to fit.

Go Up