Forum: Compiler & IDEs Optimale Stacksize bestimmen


von Christian J. (Gast)


Lesenswert?

Hallo,

die User Stacksize wird bei der Rowley Umgebung zu Anfang fix 
eingestellt.  Ebenso FIQ und IRQ Größen.

Fragt sich nur: Wie gut liegt man mit seiner Schätzung? Egal wie ich den 
Wert verändere, der Compiler und auchn Linker meckert nicht.

Wie kann man denn die Größe so bestimmen, dass sie eben optimal passt 
und man keinen wertvollen RAM verschenkt? Beim PIC Compiler rechnet der 
es aus der maximalen Verschachtelungstiefe aus, beim GCC weiss ich nicht 
wie das geht.

von Karl H. (kbuchegg)


Lesenswert?

Christian J. schrieb:

> Fragt sich nur: Wie gut liegt man mit seiner Schätzung? Egal wie ich den
> Wert verändere, der Compiler und auchn Linker meckert nicht.

Wundert mich wenig.
Wenn der Stack zu klein ist, merkst du das erst zur Laufzeit. Und das 
auch nur wenn in deinem Programm plötzlich seltsame Dinge passieren bzw. 
dein Compiler bei jedem Funktionsaufruf Code einbaut, der die Stackgröße 
überwacht und Alarm schlägt.

> Wie kann man denn die Größe so bestimmen, dass sie eben optimal passt

Gegen das Wort 'optimal' hab ich ein Aversion entwickelt.

> und man keinen wertvollen RAM verschenkt? Beim PIC Compiler rechnet der
> es aus der maximalen Verschachtelungstiefe aus, beim GCC weiss ich nicht
> wie das geht.

Die benötigte Stacksize ist im Allgemeinen nicht per Programm 
bestimmbar. Das wäre eine Variation des Turingschen Halteproblems und 
ist daher prinzipiell nicht möglich. Was nicht heißt, das es für 
einzelne Programme nicht gehen mag. Nur ist es eben nicht für jedes 
beliebige Programm möglich die benötigte Stacksize durch Betrachten des 
Source Codes zu bestimmen.

von Christian J. (elektroniker68)


Lesenswert?

Hallo,

aber irgendwie muss man doch die optimale Size bestimmen können. Wenn 
das der CCS Compiler kann, dann können das doch auch andere. Sobald die 
Abhängigkeiten bekannt sich lässt sich das ausrechnen.

von Karl H. (kbuchegg)


Lesenswert?

Christian J. schrieb:
> Hallo,
>
> aber irgendwie muss man doch die optimale Size bestimmen können.
1
#include <stdio.h>
2
3
unsigned int foo( unsigned int j )
4
{
5
  if( j == 0 )
6
    return 1;
7
8
  return foo( j - 1 );
9
}
10
11
int main()
12
{
13
  unsigned int k;
14
15
  scanf( "%u", &k );
16
  printf( "%u\n", foo( k ) );
17
}

Wie soll ein Linker daraus die "optimiale" Stacksize bestimmen können, 
wenn er nicht weiß, was der Benutzer eingeben wird?
(Der Compiler kann sowas prinzipbedingt nicht bestimmen, da er im 
Regelfall das komplette Programm nie zu Gesicht bekommt)

von Peter (Gast)


Lesenswert?

> Wenn das der CCS Compiler kann, dann können das doch auch andere.
Auch er kann es nicht, was macht er wohl bei


void test( int a ) {
   char dummy[20];
   sprintf(dummy, "%d", a);
   for( int i = a; i < 10 + strlen( dummy ); ++i ) {
      test( i+1 );
   }
}

main() {
  test(0);
}

na wieviel stack braucht du wohl, ich glaube kaum das der Compliler das 
ermitteln kann?

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Wie kann man denn die Größe so bestimmen, dass sie eben optimal passt
> und man keinen wertvollen RAM verschenkt?

Dazu muß man in die Internas des Compilers gehen.

Es gibt Compiler, die brauchen keinerlei Einstellungen. Z.B. beim 
AVR-GCC kommen unten die globalen Variablen, danach dann Malloc und der 
Stack wächst vom Ende des SRAM nach unten.
Wenn es dann kracht, hilft keine Einstellung, dann wurde zuviel Speicher 
belegt und das Malloc rennt in den Stack rein bzw. umgekehrt.

Das manche Compiler aber mehrere Stacks benötigen, dient wohl der 
Vorbereitung von Multitasking.

Da hilft wohl nur eine Analyse zur Laufzeit. Man füllt allen unbenutzten 
SRAM mit einem Muster, z.B. 0x77 und testet nach ner Weile, wieviel 
davon in den einzelnen Stacks noch übrig ist.


Peter

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:

> Das manche Compiler aber mehrere Stacks benötigen, dient wohl der
> Vorbereitung von Multitasking.

Und an der Architektur der AVRs. Da AVR keinen atomaren Update von SP 
ermöglicht, tut sich ein Compiler etwas leichter, wenn der Stack für die 
lokalen Variablen vom Return-Stack getrennt wird. Einer dieser beiden 
Stacks ist dann fix.

von kjk (Gast)


Lesenswert?

hallo ,

ich mache das so, das ich erst den speicher voll schreibe, um dann zu 
testen wieviel verändert wurde.
so kann man ungefähr abschätzen wieviel man braucht.

an pregnanten stellen testmymem("xyz"); aufrufen.

im main file:

#ifndef FLASH_RELEASE
void testmymem(char *loc){
  unsigned int* lHeapPtr = (unsigned int*) &__heap_start__;
  while (lHeapPtr)
  {
    DBG("\nheap space left %d :%s", *(lHeapPtr + 1), loc);
    lHeapPtr = (unsigned int*) *lHeapPtr;
  }

  unsigned long stack_used, irq_stack_used, fiq_stack_used, 
svc_stack_used, und_stack_used, abt_stack_used, bss_used;
  stack_used = get_stack_used(&__stack_start__, &__stack_end__);
  DBG("\nstack_used %d :%s", stack_used, loc);
  irq_stack_used = get_stack_used(&__stack_irq_start__, 
&__stack_irq_end__);
  DBG("\nirq_stack_used %d :%s", irq_stack_used, loc);
  fiq_stack_used = get_stack_used(&__stack_fiq_start__, 
&__stack_fiq_end__);
  DBG("\nfiq_stack_used %d :%s", fiq_stack_used, loc);
  svc_stack_used = get_stack_used(&__stack_svc_start__, 
&__stack_svc_end__);
  DBG("\nsvc_stack_used %d :%s", svc_stack_used, loc);
  und_stack_used = get_stack_used(&__stack_und_start__, 
&__stack_und_end__);
  DBG("\nund_stack_used %d :%s", und_stack_used, loc);
  abt_stack_used = get_stack_used(&__stack_abt_start__, 
&__stack_abt_end__);
  DBG("\nstack_stack_used %d :%s", abt_stack_used, loc);
  bss_used = get_bss_used(&__bss_start__, &__bss_end__);
  DBG("\nbss_used %d :%s", bss_used, loc);
}
#endif

im crt0.S file:
#ifdef INITIALIZE_STACKS
  mov r2, #0xCC
  ldr r0, =__stack_und_start__
  ldr r1, =__stack_und_end__
  bl memory_set
  ldr r0, =__stack_abt_start__
  ldr r1, =__stack_abt_end__
  bl memory_set
  ldr r0, =__stack_irq_start__
  ldr r1, =__stack_irq_end__
  bl memory_set
  ldr r0, =__stack_fiq_start__
  ldr r1, =__stack_fiq_end__
  bl memory_set
  ldr r0, =__stack_svc_start__
  ldr r1, =__stack_svc_end__
  bl memory_set
  ldr r0, =__stack_start__
  ldr r1, =__stack_end__
  bl memory_set
#endif

von Mark .. (mork)


Lesenswert?

A. K wrote

> Und an der Architektur der AVRs. Da AVR keinen atomaren Update von SP
> ermöglicht, tut sich ein Compiler etwas leichter, wenn der Stack für die
> lokalen Variablen vom Return-Stack getrennt wird. Einer dieser beiden
> Stacks ist dann fix.

Auch beim AVR ist ein atomarer Zugriff auf SP möglich, indem man die 
Interrupts sperrt und danach wieder freigibt. Genau das macht auch der 
avr-gcc, wenn er Platz für lokale Variablen auf dem Stack reserviert. 
Einen weiteren (Software-)Stack benutzt avr-gcc nicht.

MfG Mark

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.