static variables seems to be allocated on stack (Codewarrior for Microc.. v6.2 and Coldfire V1)

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

static variables seems to be allocated on stack (Codewarrior for Microc.. v6.2 and Coldfire V1)

2,414 Views
yomuki
Contributor I

Hi, I'm using a math function for my Coldfire MCF51QE128 under Codewarrior v6.2 and it seems it allocates static variables under stack, which makes my stack to overflow. I'm using uCOS-II as RTOS (but i think this is indifferent).

 

Here you have the piece of code wich is making me crazy. It belongs to module CAstr.c (astronomic calculations):

 

static FP64 A;               //FP64 is a double typedef
static INT32U absLat;
static INT32U absLon;
static FP64 AM;
static FP64 AR;
static FP64 C;
static FP64 D;
//... here comes more static variables shared under this module. Next function uses all these 40 variables.

 

/******************************************************************************/
/* FUNCTION:                    ComputeDawnDusk                                 */
/*****************************************************************************/
static INT8U ComputeDawnDusk(INT32U *This, CTimeDate *t, FP32 lat, FP32 lon){
    absLat = (lat < 0)? -lat : lat;
    absLon = (lon < 0)? -lon : lon;

    // date formatting from my own CTimeDate struct...   
    DD=t->date.day;
    MM=t->date.month;
    YY= 2000 + t->date.year;

    // calculating math ecuations....

    ......

    ......

}

 

As you can see all the variables used inside this function are static and has a fixed RAM position, I've verified looking at the MAP file, see below:

 

 00801680 00000008 .sbss   C    (CAstr.c)
 00801688 00000008 .sbss   AR    (CAstr.c)
 00801690 00000008 .sbss   AM    (CAstr.c)
 00801698 00000004 .sbss   absLon    (CAstr.c)
 0080169C 00000004 .sbss   absLat    (CAstr.c)
 008016A0 00000008 .sbss   A    (CAstr.c)

 

But when the function is executed, a huge stack area is reserved and i get an stack overflow. See this dissasemble of the ComputeDawnDusk function:

 

MOVE.L    A6, -(A7)

MOVE.L    A4,-(A7)

LEA         -1988(A7),A7                    //<---- THIS DISPLACEMENT CAUSES THE STACK OVF.

MOVEA.L   2004(A7),A4

CLR.L        4(A7)

MOVE.L      2008(A7),(A7)

.........

 

 I've been trying to use other kind of declaration for such variables (volatile, global) and continuosly occurs the same. It seems as if the compilers optimize the code and uses the stack to store all of such variables, causing the overflow.

 

Please, could you help me with this stuff. Thanks a lot.

Labels (1)
0 Kudos
4 Replies

444 Views
CompilerGuru
NXP Employee
NXP Employee

The compiler is probably using that stack area for other things than for the static variables.

For example temporaries (e.g. in a=(b+c)*d; the location (b+c)), spills, parameters, temporary objects (especially in C++) and more. I guess the reason why the compiler does allocate so many variables is in the non-shown part of the compiler. Check the generated code what the stack is used for. Are there any large things which may get allocated on the stack? For example strings?

 

Daniel

0 Kudos

444 Views
yomuki
Contributor I

Yes I've checked and the compiler stacks around 2KB of auxiliary data for such operations. 2KBytes!!! I think this is a crazyness.

 

The function ComputeDawnDusk executes several math ecuations using functions as sin, cos, acos, atan and so on. Firstly I used the precompiled math library for the QE128 but its footprint was around 32KBytes of code (incredible!!!!). After that I prepared my own math library reducing such footprint up to 8KBytes ( a more reasonable solution). Nevertheless 2KBytes of stack for this function.... well i'm already surprised.

 

I paste below the full source code of this function so that you can evaluate if really 2KBytes of stack seems to be necessary. I've checked the dissasembly code and all the operations are carried out using the internal registers D0..D7, A0..A5. But after the execution of the function is true that nearly 2KBytes of stack have been filled with temporary data.

 

Is there something inside the compiler that I can configure to reduce this huge stack??. Exist any math library for the QE128 with a low footprint to use under constraint resources??

 

As I explained I'm using uCOS-II and I keep running 3 tasks in parallel. Each task consumes around 1 to 2KBytes of RAM and this microcontrollers has up to 8KBytes. If only this function requires 2KBytes of stack I must sure that the task who invoques the function must have 2KBytes more and right now this is impossible because the application is nearly finished and the RAM is highly optimised and occupied.

 

//-------------------source code

static volatile FP64 A;
static volatile INT32U absLat;
static volatile INT32U absLon;
static volatile FP64 AM;
static volatile FP64 AR;
static volatile FP64 C;
static volatile FP64 D;
static volatile FP64 DC;
static volatile FP64 DCOC;
static volatile FP64 DCOR;
static volatile FP64 DD;
static volatile FP64 ET;
static volatile FP64 F;
static volatile FP64 GGG;
static volatile FP64 G1;
static volatile FP64 H;
static volatile FP64 HC;
static volatile FP64 HO;
static volatile FP64 HOC;
static volatile FP64 HOR;
static volatile FP64 HORTO;
static volatile FP64 JD;
static volatile FP64 J1;
static volatile FP64 J2;
static volatile FP64 L;
static volatile FP64 Lat;
static volatile FP64 Lon;
static volatile FP64 M;
static volatile FP64 MC;
static volatile FP64 MM;
static volatile FP64 MOC;
static volatile FP64 MOR;
static volatile FP64 MR;
static volatile FP64 M1;
static volatile FP64 OB;
static volatile FP64 P;
static volatile FP64 R;
static volatile FP64 S;
static volatile FP64 S1;
static volatile FP64 TO;
static volatile FP64 TUC;
static volatile FP64 TUOC;
static volatile FP64 TUORTO;
static volatile FP64 V;
static volatile FP64 VD;
static volatile FP64 VDOC;
static volatile FP64 VDOR;
static volatile FP64 VHOC;
static volatile FP64 VHORTO;
static volatile FP64 YY;
static volatile FP64 Z;
/******************************************************************************/
/* FUNCTION:                    ComputeDawnDusk                                 */
/*****************************************************************************/
INT8U ComputeDawnDusk(INT32U*This, CTimeDate *t , FP32 lat, FP32 lon){
    absLat = (lat < 0)? -lat : lat;
    absLon = (lon < 0)? -lon : lon;

    // formatea la fecha   
    DD=t->date.day;
    MM=t->date.month;
    YY= 2000 + t->date.year;

    // get latitude and longitude

    Lon=lon;
    Lat= lat;
   
    // calculate julyan date

   GGG = 1;
    if (YY <= 1585){
        GGG = 0;
    }
    JD = -1 * floor(7 * (floor((MM + 9) / 12) + YY) / 4);
    S = 1;
    if ((MM - 9)<0){
         S=-1;
    }
    A = (MM - 9 >= 0)? (MM-9) : (9-MM); //abs
    J1 = floor(YY + S * floor(A / 7));
    J1 = -1 * floor((floor(J1 / 100) + 1) * 3 / 4);
    JD = JD + floor(275 * MM / 9) + DD + (GGG * J1);
    JD = JD + 1721027 + 2 * GGG + 367 * YY - 0.5;
    J2=JD;
   
    // asign Earth's static parameters

    S = 2415020.5;
    ET = 0.016718;
    P = 4.93204;
    P = P+(J2-TO)*VP/100;
    AM = M0+MN*(J2-TO);
    AM = AM-2*PI*floor(AM/(2 * PI));

    // Kepler ecuation for the Earth

    V=AM+2*ET*sin(AM)+1.25*ET*ET*sin(2*AM);
    if (V<0){
        V=2*PI+V;
    }

    L=P+V;
    L=L-2*PI*floor(L/(2*PI));

    // calculate degrees AR and DEC
    Z=(J2-2415020.5)/365.2422;
    OB=23.452294-(0.46845*Z+0.00000059*Z*Z)/3600;
    OB = OB/RAD;
    DC=asin(sin(OB)*sin(L));
    AR=acos(cos(L)/cos(DC));
    if (L>PI){
        AR=2*PI-AR;
    }

    OB=OB*RAD;
    L=L*RAD;
    AR = AR * 12 / PI;

    //convert h.ms of AR
    H=floor(AR);
    M=floor((AR - floor(AR)) * 60);
    S=((AR -floor(AR)) * 60 - M) * 60;
    DC=DC*RAD;

    // convert g.ms of DEC
    D = (DC >= 0)? DC : -DC;    //abs
    G1;
    if (DC>0){ 
        G1=floor(D);
    }
    else{
        G1=(-1)*floor(D);
    }
    M1=floor((D - floor(D)) * 60);
    S1 = ((D - floor(D)) * 60 - M1) * 60;

    if (DC<0){
        M1=-M1;
        S1=-S1;
    }

    // calculate time curve
       MR = 0.04301;
    F=13750.987;
    C=2*ET*F*sin(AM)+1.25*ET*ET*F*sin(2*AM);
    R=-MR*F*sin(2*(P+AM))+MR*MR*F*sin(4*(P+AM))/2;
    ET=C+R;

    // calculate semi-daily arc

    HO=acos(-tan(Lat/RAD)*tan(DC/RAD));
    HO=HO*RAD;

    // declination variation
    VD=0.9856*sin(OB/RAD)*cos(L/RAD)/cos(DC/RAD);
   
    // DAWN calculation
    VDOR=VD*(-HO+180)/360;
    DCOR=DC+VDOR;
    HORTO=-acos(-tan(Lat/RAD)*tan(DCOR/RAD));
    VHORTO=5/(6*cos(Lat/RAD)*cos(DCOR/RAD)*sin(HORTO));
    HORTO=(HORTO*RAD+VHORTO)/15;
     TUORTO=HORTO+ET/3600-Lon/15+12;

    // convert h.m of dawn
    HOR=floor(TUORTO);
    MOR=floor((TUORTO - HOR) * 60+0.5);

    // cálculo de la culminación
    TUC=12+ET/3600-Lon/15;

    // convert  h.m of highest sun position

    HC=floor(TUC);
    MC=floor((TUC - HC) * 60+0.5);

    // dusk calculation
    VDOC=VD*(HO+180)/360;
    DCOC=DC+VDOC;
    HOC=acos(-tan(Lat/RAD)*tan(DCOC/RAD));
    VHOC=5/(6*cos(Lat/RAD)*cos(DCOC/RAD)*sin(HOC));
    HOC=(HOC*RAD+VHOC)/15;
    TUOC=HOC+ET/3600-Lon/15+12;

    // convert h.m of dusk

    HOC=floor(TUOC);
    MOC=floor((TUOC - HOC) * 60+0.5);

    return 0;
}
 

 

Thanks again.

0 Kudos

444 Views
Lundin
Senior Contributor IV
To be blunt, that isn't the compiler's fault, it is your code that is inefficient.

- You effectively disable every single chance for the compiler to optimize the code by making everything volatile.
- You should split that giant function into several small functions. All those static variables can't possibly be needed to exist throughout the whole execution of the program.
- You use huge floating point numbes for simple integer operations, such as addition, subtraction and multiplication. The only part of your code needing float numbers is the trig functions. Everything else could be rewritten as int operations. This will not only save memory but also greatly improve execution time.
- You mention that you run several tasks at once. Therefore it should be of interest to reduce the number of statics/globals to a minimum, since they can't be used for multitasking.
0 Kudos

444 Views
yomuki
Contributor I

Hi Lundin, yes you are right about to split the function in several smaller ones .It'd probably go well. It is a solution I was in mind. I go with it.

 

About optimization due to volatile, and that the compiler is going well,  you are right too, but I posted the last version. I tested without volatile, only with static qualifier and even local to the function (to be stored in stack and registers) and everything behaves the same, what implies that a lot of temporary intermediate data is required by the giant function and splitting it could be the solution as you say.

 

An yes again, I could reduce the size of the data to save memory and speed, but this is a process executed once a day and I launch it under a low priority daemon, so I have a 24h deadline to complete, so speed is not a constraint for me within this function.

 

Thank you so much for your comments.

0 Kudos