www.mikrocontroller.net

Forum: Compiler & IDEs Performance - großes switch-statement - jump-table ?


Autor: balu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

als Anfänger in der Embedded Programmierung habe ich eine (vielleicht 
triviale) Frage bei der mir sicher jemand einen Tip geben kann?

Innerhalb meines Programms befindet sich ein großes switch-statement, 
das sehr häufig ausgeführt wird. Der Wertebereich über den "geswitched" 
wird erstreckt sich von 0-256, die einzelnen Cases(werte) sind 
allerdings nicht unbedingt aufeinanderfolgend. Avr-gcc scheint mir immer 
ein binary-search daraus zu generieren ich hätte aber lieber einen 
jump-table o.ä. Ich konnte avr-gcc allerdings nie dazu bewegen einen 
jump-table zu generieren  auch wenn der Wertebereich über den der switch 
ging voll ausgeschöpft war.

Als nächstes habe ich versucht gcc's label-as-value zu verwenden (jeder 
case ein label, ein array mit allen labels erstellen ala &&LABEL... und 
dann mit dem Wert der switch-expression in das array mit goto * 
array[expr] springen). Das hat allerdings den großen Nachteil, dass ich 
das Array im RAM halten muss (was für einen atmega128 ca. 512 byte 
bedeutet).

Was macht man in so einem Fall typischerweise? Wieso verwendet avr-gcc 
(4.1.2) keine jump-tables? Könnte ich nicht ein vielfaches der 
switch-expression(0-256) im Programmcode springen und von dort über das 
Label den jeweiligen Fall abarbeiten?

Gruß Balu

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man könnte das auch mit Funktionspointern in einem Array machen. Die 
kann man problemlos in den Flash packen und es macht die Sache 
übersichtlicher.

MFG
Falk

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Läss sich das goto nicht mit Array im ROM und pgm_read_word oder so 
kombinieren?

Autor: balu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die schnelle Antwort,

ist das ganze dann nicht wieder langsamer dadurch, dass auf den Flash
zugegriffen werden muss? Im Endeffekt müsst ich aber nur 16-bit lesen 
oder?

Gruß Balu

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Flash lesen ist kaum langsamer als indirekt RAM lesen, insgesamt um 2 
Takte nehme ich an. Und bei der von dir gesuchten switch-table wär's ja 
auch nicht anders.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Möglicherweise fehlt avr-gcc das Pattern "tablejump", wobei das "casesi" 
vorhanden ist, sollte also gehen.
Aber 100% sicher bin ich da nicht, ob das casesi auch funzt ohne 
tablejump, müsste ich durch gcc durch...

Ob man von aussen per --param an die Thresholds kommt, hab ich auf die 
schnelle auch net gesehen in der gcc-Doc. Hab leider keine Quelle hier 
zum greppen.

Computed goto-Labels kannst du auch ins Flash legen. Das ist vielleicht 
übersichtlicher als 256 Funktionen. Das Beispiel ist für 16-Bit PC und 
GNU-C.
#include <avr/pgmspace.h>

#if (__GNUC__ > 3) && !defined (__AVR_2_BYTE_PC__)
#error Nur fuer 2-Byte PC
#endif

uint16_t bar (uint16_t i)
{
    static const void ** labels[] PROGMEM = 
    {
        && label0,
        && label1
    };
    
    if (i < sizeof (labels) / sizeof (labels[0]))
    {
        void ** addr = (void**) pgm_read_word (& labels[i]);
        goto *addr;
    }
    
    return 0;
    
    
    label1:
        return 2;
        
    label0:
        return i+1;
}

Das Lesen aus dem Flash kostet pro Byte (incl. evtl. post-inc) 1 
Taktzyklus.

Die Adressberechnung ist da nicht mitgerechnet, die kostet bei der 
RAM-Variante aber das gleiche.

Johann

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibts nen Grund warum man einen doppelten Zeiger verwenden muss bei der 
Geschichte?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon K. schrieb:
> Gibts nen Grund warum man einen doppelten Zeiger verwenden muss bei der
> Geschichte?

Muss man glaub garnicht. Sowas müsste auch gehen:
    if (i)
      goto *((void*) 0);
    else
      goto *((void*) bar);

Ich faand's nur seltsam, void* zu schreiben, weil man ja dereferenziert 
und ein void-Objekt bekommt. Das kenn ich nur von
   (void) i;

Autor: Balu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an alle! Hat funktioniert. Viel schneller als das große 
Switch-statement ist es leider nicht, dafür ist der Code aber um einiges 
kleiner.
Gruß Balu

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.