Difference between revisions of "BoostC Optimizations"

From OpenCircuits
Jump to navigation Jump to search
Line 12: Line 12:
  
  
A few common ones i remember offhand:
+
==== Incrementing ====
  
==== Incrementing =====
+
subtracting/deincrementing is faster than adding/incrementing
  
 +
Valid?  believed not to be true
  
-subtracting/deincrementing is faster than adding/incrementing
+
==== Avoid Division ====
  
believed not to be true
+
not using division saves ~35 bytes
  
==== Avoid Division =====
+
Valid?  division is slow, but we think not by poweres of 2, which are shifts ( if divisor know at compile time )
  
-not using division saves ~35bytes
+
==== Left vs Right Shift ====
 
 
division is slow, but not by poweres of 2, which are shifts ( if divisor know at compile time )
 
 
 
==== Left vs Right Shift =====
 
  
 
Left Shifting is faster than Right
 
Left Shifting is faster than Right
Line 33: Line 30:
 
==== Function call in ISR =====
 
==== Function call in ISR =====
  
-Calling a function in an ISR takes longer than outside an ISR
+
Calling a function in an ISR takes longer than outside an ISR
 
+
Valid?  believed not to be true
  
 
==== Function called Only Once =====
 
==== Function called Only Once =====
  
 
-Never use a function for a single operation, you waste time calling and returning
 
-Never use a function for a single operation, you waste time calling and returning
 +
 +
Valid?  believed not to be true
  
 
==== Shift for Division =====
 
==== Shift for Division =====
  
-Use bit shifting instead of division for speed savings and possible ram savings
+
Use bit shifting instead of division for speed savings and possible ram savings
 
 
  
 
(shifting one bit right is equal to dividing by two, etc)
 
(shifting one bit right is equal to dividing by two, etc)
  
 +
Valid?  believed not to be true, optimizer is smart enough to do this
  
  
 +
==== Arrays and Pointers ====
  
 
+
Both arrays and pointers generate a lot of code. Use plain variables instead where possible.
 
 
 
 
 
 
 
 
 
 
 
 
I dont think any of these are valid optimisations with BoostC.
 
 
 
QUOTE (emte @ Dec 19 2006, 07:18 AM)
 
-subtracting/deincrementing is faster than adding/incrementing
 
-Left Shifting is faster than Right
 
-Calling a function in an ISR takes longer than outside an ISR
 
 
 
 
 
 
 
 
 
BoostC performs additional optimisations on shift operations.  
 
 
 
QUOTE (emte @ Dec 19 2006, 07:18 AM)
 
-Use bit shifting instead of division for speed savings and possible ram savings
 
    (shifting one bit right is equal to dividing by two, etc)
 
 
 
 
 
  
 
I just saved a lot of bytes by reducing the number of index access on array vars.
 
I just saved a lot of bytes by reducing the number of index access on array vars.
  
 
a stupid and useless example:
 
a stupid and useless example:
char var[10];
 
  
for( i= 0; i<10;i++){
+
  char var[10];
if ((var[i]==this) || (var[i]==that)) var[i]=somefunction(var[i]);
+
 
var[i]+=2;
+
  for( i= 0; i<10;i++){
}
+
      if ((var[i]==this) || (var[i]==that)) var[i]=somefunction(var[i]);
 +
      var[i]+=2;
 +
  }
  
  
 
if you need to have access on a particular index several times i'm using an extra dummy var.
 
if you need to have access on a particular index several times i'm using an extra dummy var.
  
char var[10], dummy;
+
  char var[10], dummy;
 
+
 
for( i= 0; i<10;i++){
+
  for( i= 0; i<10;i++){
dummy= var[i];
+
      dummy= var[i];
if ((dummy==this) || (dummy==that)) dummy=somefunction(dummy);
+
      if ((dummy==this) || (dummy==that)) dummy=somefunction(dummy) {
var[i]= dummy+=2;
+
        var[i]= dummy+=2;
}
+
      }
 +
  }
  
 
something similar happens when you are working with struct variables.
 
something similar happens when you are working with struct variables.
 
 
 
 
  
  
Here are a few tricks that can reduce code size a lot:
 
  
1. Use smallest data type possible. For example if 8 bits is enough use char and not short or long.
 
2. Use unsigned data types if possible. Unsigned types generate shorter code than signed.
 
3. Both arrays and pointers generate a lot of code. Use plain variables instead where possible.
 
 
Regards,
 
Pavel
 
  
 +
==== ROM vs RAM ====
 +
-Write constants into ROM not RAM
  
 +
Valid?  In that you save RAM at the expense of ROM, normally you have more ROM than RAM.
  
 +
==== Return Values ====
  
Group: EstablishedMember
+
Do not return values from functions that you wont use/do not need.
Posts: 378
 
Joined: 8-December 06
 
From: Victoria, BC, Canada
 
Member No.: 2,230
 
  
 +
Valid?  We think so, seems like it must be.
  
QUOTE (Pavel @ Dec 21 2006, 03:54 PM)
 
Here are a few tricks that can reduce code size a lot:
 
  
1. Use smallest data type possible. For example if 8 bits is enough use char and not short or long.
+
==== ROM vs RAM ====
2. Use unsigned data types if possible. Unsigned types generate shorter code than signed.
 
3. Both arrays and pointers generate a lot of code. Use plain variables instead where possible.
 
  
Regards,
 
Pavel
 
  
 
 
To add onto this list a bit:
 
-Write constants into ROM not RAM
 
-Do not return values from functions that you wont use/do not need
 
 
-Reuse common code or write a common function and call it will save huge amounts of space
 
-Reuse common code or write a common function and call it will save huge amounts of space
 
( i suspect agressive opt in BoostC may negate this last but i've yet to test)
 
( i suspect agressive opt in BoostC may negate this last but i've yet to test)
  
 +
Valid?  We think so, but even if not it good coding pratice.
  
  
Line 167: Line 126:
  
  
 
 
QUOTE (emte @ Dec 27 2006, 05:07 PM)
 
 
i had forgotten about this one but the good old ()?:; (tri-unary?) function conditionally yields slightly smaller/faster code...
 
i had forgotten about this one but the good old ()?:; (tri-unary?) function conditionally yields slightly smaller/faster code...
  
Line 181: Line 137:
 
   
 
   
 
   
 
   
 
 
 
 
  
 
QUOTE (edt @ Dec 29 2006, 01:23 PM)
 
QUOTE (edt @ Dec 29 2006, 01:23 PM)
Line 250: Line 202:
 
Hmm it looks like the if-else might actually be one line shorter now ... altho it is
 
Hmm it looks like the if-else might actually be one line shorter now ... altho it is
 
just a lable line.  
 
just a lable line.  
 
 
 
  
  
 
result= test&1;
 
result= test&1;
 
 
  
  
Line 270: Line 218:
 
conversion)
 
conversion)
 
... hmm maybe i should add that example to handy functions ...
 
... hmm maybe i should add that example to handy functions ...
 +
 +
 +
 +
==== Still More we are working on ====
 +
 +
 +
Software stack is slower than hardware ( but deeper )
 +
 +
Valid? we think so.
 +
 +
Inline function does not really use call and return so is faster, but if called multiple time may take more space ( but for short funtions the call return... can take more space than the function itself.  Would be nice if someone did measurements.
 +
 +
Valid? we think so.
 +
 +
 +
Local values vs global variables.

Revision as of 20:41, 12 February 2009




some notes from the forum still to be formatted

The following post yeilded several real and unreal optimizations http://forum.sourceboost.com/index.php?showtopic=2433&pid=9574&mode=threaded&start=#entry9574


Incrementing

subtracting/deincrementing is faster than adding/incrementing

Valid? believed not to be true

Avoid Division

not using division saves ~35 bytes

Valid? division is slow, but we think not by poweres of 2, which are shifts ( if divisor know at compile time )

Left vs Right Shift

Left Shifting is faster than Right

Function call in ISR =

Calling a function in an ISR takes longer than outside an ISR Valid? believed not to be true

Function called Only Once =

-Never use a function for a single operation, you waste time calling and returning

Valid? believed not to be true

Shift for Division =

Use bit shifting instead of division for speed savings and possible ram savings

(shifting one bit right is equal to dividing by two, etc)

Valid? believed not to be true, optimizer is smart enough to do this


Arrays and Pointers

Both arrays and pointers generate a lot of code. Use plain variables instead where possible.

I just saved a lot of bytes by reducing the number of index access on array vars.

a stupid and useless example:

  char var[10];
  
  for( i= 0; i<10;i++){
     if ((var[i]==this) || (var[i]==that)) var[i]=somefunction(var[i]);
     var[i]+=2;
  }


if you need to have access on a particular index several times i'm using an extra dummy var.

  char var[10], dummy;
  
  for( i= 0; i<10;i++){
     dummy= var[i];
     if ((dummy==this) || (dummy==that)) dummy=somefunction(dummy)  {
        var[i]= dummy+=2;
     }
  }

something similar happens when you are working with struct variables.



ROM vs RAM

-Write constants into ROM not RAM

Valid? In that you save RAM at the expense of ROM, normally you have more ROM than RAM.

Return Values

Do not return values from functions that you wont use/do not need.

Valid? We think so, seems like it must be.


ROM vs RAM

-Reuse common code or write a common function and call it will save huge amounts of space ( i suspect agressive opt in BoostC may negate this last but i've yet to test)

Valid? We think so, but even if not it good coding pratice.


i had forgotten about this one but the good old ()?:; (tri-unary?) function conditionally yields slightly smaller/faster code on every compiler i've ever used versus using if()else(); The gain varies from 1-3 lines of asm code, which, if in a high use test will amount to a conciderable savings.

The conditional aspect of this is that the fail function must do something it cannot be left empty or there is no value in using it and will actually result in longer code.

CODE (test)?(result=1):(result=0);

VS CODE if(test) {

  result=1;

} else {

  result=0;

}


i had forgotten about this one but the good old ()?:; (tri-unary?) function conditionally yields slightly smaller/faster code...

I tried that one out and there's no gain on SourceBoost C (for PIC16) on any optimization level.

For code like that, I would expect this: CODE result = (test ? 1 : 0) to do better, but it doesn't, either...



QUOTE (edt @ Dec 29 2006, 01:23 PM) QUOTE (emte @ Dec 27 2006, 05:07 PM) i had forgotten about this one but the good old ()?:; (tri-unary?) function conditionally yields slightly smaller/faster code...

I tried that one out and there's no gain on SourceBoost C (for PIC16) on any optimization level.

For code like that, I would expect this: CODE result = (test ? 1 : 0) to do better, but it doesn't, either...



Odd, altho my tests were simply:

CODE

   (testBit)?(_ONE = 1):(_ONE = 0);

0039 08A1 MOVF main_1_testBit, F 003A 1903 BTFSC STATUS,Z 003B 283E GOTO label268438744 003C 1486 BSF gbl__ONE,1 003D 283F GOTO label268438746 003E label268438744 003E 1086 BCF gbl__ONE,1 003F label268438746

       if(testBit)

003F 08A1 MOVF main_1_testBit, F 0040 1903 BTFSC STATUS,Z 0041 2844 GOTO label268438747 0044 label268438747

       {
           _ONE = 1;

0042 1486 BSF gbl__ONE,1

       }
       else

0043 2837 GOTO label268438739

       {
           _ONE = 0;

0044 1086 BCF gbl__ONE,1

       }


with the asm disassembly, but it looks like i am wrong about the new version of the compiler. i am glad to see that these are now the same as they are identical chunks of code.

If i recall correctly, the reason they were different is that the if-else used to use two bit tests to determine logic, which is how you would do it if you had more ifelse tests.

Now i am back to using ?:; just for a cleaner look to code i guess. Thanks for testing that with the new version, it did not even occur to me that it may have changed



Hmm it looks like the if-else might actually be one line shorter now ... altho it is just a lable line.


result= test&1;


Yes that would possibly work in this case as it is an extremly simple example. But on the otherhand if you were writting code for an indicator light, say to notify of an AD conversion, you could not use the return value as your test bit. ie. if test = 4 that mask would fail but (test)?(result=1):(result=0); would work since all non-zero/positives would set result.

i find this handy if you have more than one AD module on your device instead of using the flags as you can now build an AD FIFO cyclical stack or non-blocking time sensitive functions. (all that slow eeprom write stuff while your doing another conversion) ... hmm maybe i should add that example to handy functions ...


Still More we are working on

Software stack is slower than hardware ( but deeper )

Valid? we think so.

Inline function does not really use call and return so is faster, but if called multiple time may take more space ( but for short funtions the call return... can take more space than the function itself. Would be nice if someone did measurements.

Valid? we think so.


Local values vs global variables.