mikrocontroller.net

Forum: Compiler & IDEs GCC Optimierung


Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,

ich habe nachfolgende komplexe C Funktion und ein par Fragen in 
grundsätzlicher Art zur Optimierung.

In der Funktion deklariere ich einige Variablen gleich am Anfang der 
Funktion und auch später bei Bedarf. Die Frage ist ob es besser für die 
GCC Optimierungs Möglichkeiten ist diese Variablen alle am Anfang zu 
deklarieren oder so wie ich es jetzt gemacht habe, zwischendrin bei 
Bedarf ? Oder ist das egal ?

Desweiteren greife ich sehr oft auf eine globale Struktur "glcd" zu. 
Einige wichtige Member dieser Struktur habe ich schon als Kopie in 
lokale Variablen genommen. Die Frage ist ob es für die Optimierung des 
GCC nun besser ist alle notwendigen Member ebenfalls in lokale Variablen 
zu übernehmen ? Es würde ja dann ein sehr großer Registerdruck für den 
GCC entstehen und dadurch eventuell gerade in den wichtigen Schleifen 
die Register ausgehen können und somit sehr langsamme Schleifen 
entstehen.

Alle GLCD_???? Aufrufe sind Makros und inplaced.
void glcdPrint(const prog_char* string, uint8_t flashstored) {

    if ((glcd.FontData == 0) | (string == 0)) return;

    uint8_t flags = (flashstored == 0 ? 0x30 : 0x70) | (glcd.FontBitsPixel & 0x80) | (glcd.Flags.All & 0x0F);
    uint8_t c, i, FontHeight = glcd.FontHeight;
    while (1) {
      if (flags & 0x40) c = pgm_read_byte(string);
        else c = *string;
      if (!(c)) break;
      string++;
      if (c == '\n') {
        glcd.Cursor.x  = glcd.Window.x1;
        glcd.Cursor.y += FontHeight;
        if (glcd.Cursor.y + FontHeight > glcd.Window.y2) glcd.Cursor.y = glcd.Window.y1;
        flags |= 0x10;  // invalidate LCD address pointer
        continue;
      }
      if ((c < glcd.FontFirstChar) | (c > glcd.FontLastChar)) continue;
      uint8_t charwidth = GLCD_READFUNC(glcd.FontData + GLCD_FONT_HEADER_SIZE + (c - glcd.FontFirstChar));
      if (!(charwidth)) continue;
      uint8_t width = charwidth;
      if (c < 128) width++;
      if ((flags & 0x01) & (width < glcd.FontWidth)) width = glcd.FontWidth;  // FixedFont ??
      if ((flags & 0x02) & (glcd.Cursor.x + width >= glcd.Window.x2)) {  // LineFeed ??
        glcd.Cursor.x  = glcd.Window.x1;
        glcd.Cursor.y += FontHeight;
        if (glcd.Cursor.y + FontHeight > glcd.Window.y2) glcd.Cursor.y = glcd.Window.y1;
        flags |= 0x10;  // invalidate LCD address pointer
      }
      uint16_t bits;
      glcdFontData_t data;  // Achtung! wenn der Font zb. auf Devices mit mehr als 64Kb FLASH oberhalb von 64Kb gespeichert ist muß das hier auf uint32_t und GLCD_READFUNC() angepasst werden
      uint8_t bitspixel = glcd.FontBitsPixel & 0x7F, bitsmask = 0xFF >> (8 - bitspixel), bitscount, RLE[4], charofs = glcd.FontLastChar - glcd.FontFirstChar;
      if (flags & 0x80) { // compressed Font ??
        data = glcd.FontData + (GLCD_FONT_HEADER_SIZE +1) + charofs;
        uint8_t padding = GLCD_READFUNC(data++);
        RLE[0] = 1;
        RLE[1] = GLCD_READFUNC(data++);
        RLE[2] = GLCD_READFUNC(data++);
        RLE[3] = GLCD_READFUNC(data++);
        uint32_t index = 0;
        for (i = glcd.FontFirstChar; i < c; i++) index += GLCD_READFUNC(data++);
        index *= padding;
        data = glcd.FontData + (GLCD_FONT_HEADER_SIZE +6) + (charofs *2) + index;
        bits = GLCD_READFUNC(data++);
        bitscount = 8;
      } else {
        data = glcd.FontData + GLCD_FONT_HEADER_SIZE;
        uint32_t index = 0;
        for (i = glcd.FontFirstChar; i < c; i++) index += GLCD_READFUNC(data++);
        index *= FontHeight * bitspixel;
        bitscount = index % 8;
        index /= 8;
        data = glcd.FontData + (GLCD_FONT_HEADER_SIZE +1) + charofs + index;
        bits = GLCD_READFUNC(data++) >> bitscount;
        bitscount = 8 - bitscount;
      }
      if (flags & 0x20) { // inialize LCD ??
        flags ^= 0x20;
        GLCD_CS_ON();
      #ifdef GLCD_ROTATE
        GLCD_SETMODE(0x37);
      #else
        GLCD_SETMODE(0x3F);
      #endif
        GLCD_SETCOMPARE(NONE);
      }
      if (flags & 0x10) { // LCD address pointer invalid ??
        flags ^= 0x10;
        GLCD_CS_PULSE();
      #ifdef GLCD_ROTATE
        GLCD_WINDOW(glcd.Cursor.y, glcd.Cursor.x, glcd.Cursor.y + FontHeight -1, GLCD_RIGHT);
        GLCD_SETADDR(glcd.Cursor.y, glcd.Cursor.x);
      #else
        GLCD_WINDOW(glcd.Cursor.x, glcd.Cursor.y, GLCD_RIGHT, glcd.Cursor.y + FontHeight -1);
        GLCD_SETADDR(glcd.Cursor.x, glcd.Cursor.y);
      #endif
        GLCD_STARTDATA();
      }
      glcd.Cursor.x += width;
      uint8_t leftwidth = 0;
      uint8_t rightwidth = width - charwidth;
      if (flags & 0x01) { // FixedFont ??
        leftwidth = rightwidth / 2;
        rightwidth -= leftwidth;
      }
      uint8_t ch,cl;
      ch = glcd.Colors[0] >> 8;
      cl = glcd.Colors[0] & 0xFF;
      for (; leftwidth > 0; leftwidth--) {
        for (i = FontHeight; i > 0; i--) {
          GLCD_WAIT();
          GLCD_OUT(ch);
          GLCD_WAIT();
          GLCD_OUT(cl);
        }
      }
      uint8_t pixelcount = 0;
      for (; charwidth > 0; charwidth--) {
        for (i = FontHeight; i > 0; i--) {
          if (!(pixelcount)) {
            pixelcount++;
            while (bitscount <= 8) {
              bits |= GLCD_READFUNC(data++) << bitscount;
              bitscount += 8;
            }
            if (flags & 0x80) { // compresed Font ??
              pixelcount = RLE[bits & 0x03];
              bits >>= 2;
              bitscount -= 2;
            }
            bitscount -= bitspixel;
            uint8_t j = bits & bitsmask;
            ch = glcd.Colors[j] >> 8;
            cl = glcd.Colors[j] & 0xFF;
            bits >>= bitspixel;
          }
          pixelcount--;
          GLCD_WAIT();
          GLCD_OUT(ch);
          GLCD_WAIT();
          GLCD_OUT(cl);
        }
      }
      ch = glcd.Colors[0] >> 8;
      cl = glcd.Colors[0] & 0xFF;
      for (; rightwidth > 0; rightwidth--) {
        for (i = FontHeight; i > 0; i--) {
          GLCD_WAIT();
          GLCD_OUT(ch);
          GLCD_WAIT();
          GLCD_OUT(cl);
        }
      }
      GLCD_WAIT();
    }
    if (!(flags & 0x20)) { // have LCD initialized, anything done ??
      GLCD_CS_PULSE();
      GLCD_RESETWINDOW();
      GLCD_SETMODE(0x30);
      GLCD_CS_OFF();
    }
}

Gruß Hagen

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Frage ist ob es besser für die> GCC Optimierungs Möglichkeiten ist
> diese Variablen alle am Anfang zu deklarieren oder so wie ich es jetzt
> gemacht habe, zwischendrin bei Bedarf ? Oder ist das egal ?

Vom Prinzip her würde ich davon ausgehen, dass es potenziell besser ist, 
wenn die Variablen eine möglichst kurze Lebensdauer haben. Ich denke 
aber, dass es in der Praxis egal ist, weil der Optimizer sowieso 
ermittelt, von wo bis wo die Variable wirklich gebraucht wird und den 
Code entsprechend optimiert.

> Die Frage ist ob es für die Optimierung des GCC nun besser ist alle
> notwendigen Member ebenfalls in lokale Variablen zu übernehmen ?

Falls die Struktur volatile ist, ja. Wenn nicht, macht der Compiler das 
eh schon selbst implizit. Da kann es möglicherweise sogar besser sein, 
dem Optimizer nicht zu sehr ins Handwerk zu pfuschen.

>    RLE[1] = GLCD_READFUNC(data++);
>    RLE[2] = GLCD_READFUNC(data++);
>    RLE[3] = GLCD_READFUNC(data++);

Ich kenne den Inhalt des Makros nicht, aber wenn innerhalb eines 
Makro-Arguments sowas wie ++ gemacht wird, geht bei mir das rote 
Warnlicht an. Ich denke da immer an sowas wie:

#define SQUARE(x) ((x)*(x))

SQUARE(wert++);  // undefiniertes Verhalten

Übrigens: Inline-Funktionen sind zwar nur selten schneller als Makros, 
aber nie langsamer. Sie haben aber die bei Makros üblichen Probleme 
nicht.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke das klärt einiges und per praktichen Tests konnte ich das 
verifizieren.

>> GLCD_READFUNC(data++)

#define  GLCD_READFUNC(addr)   pgm_read_byte(addr)

Inline ging in diesem Falle nicht so gut da ich über die Makros den 
Source auch auf anderen Plattformen, oder für FLASH Zugriffe > 64Kb, 
oder für Speicherzugriffe auf SRAM oder ganz andere Speichermedien, 
konfigurierbar halten wollte. Und wenn ich das richtig sehe kann ich das 
Makro so umschreiben das es eine Inline oder Statische Funktion aufruft 
aber nicht umgekehrt, oder doch ?

Gruß Hagen

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.