Forum: Compiler & IDEs GCC Optimierung


von Hagen R. (hagen)


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.
1
void glcdPrint(const prog_char* string, uint8_t flashstored) {
2
3
    if ((glcd.FontData == 0) | (string == 0)) return;
4
5
    uint8_t flags = (flashstored == 0 ? 0x30 : 0x70) | (glcd.FontBitsPixel & 0x80) | (glcd.Flags.All & 0x0F);
6
    uint8_t c, i, FontHeight = glcd.FontHeight;
7
    while (1) {
8
      if (flags & 0x40) c = pgm_read_byte(string);
9
        else c = *string;
10
      if (!(c)) break;
11
      string++;
12
      if (c == '\n') {
13
        glcd.Cursor.x  = glcd.Window.x1;
14
        glcd.Cursor.y += FontHeight;
15
        if (glcd.Cursor.y + FontHeight > glcd.Window.y2) glcd.Cursor.y = glcd.Window.y1;
16
        flags |= 0x10;  // invalidate LCD address pointer
17
        continue;
18
      }
19
      if ((c < glcd.FontFirstChar) | (c > glcd.FontLastChar)) continue;
20
      uint8_t charwidth = GLCD_READFUNC(glcd.FontData + GLCD_FONT_HEADER_SIZE + (c - glcd.FontFirstChar));
21
      if (!(charwidth)) continue;
22
      uint8_t width = charwidth;
23
      if (c < 128) width++;
24
      if ((flags & 0x01) & (width < glcd.FontWidth)) width = glcd.FontWidth;  // FixedFont ??
25
      if ((flags & 0x02) & (glcd.Cursor.x + width >= glcd.Window.x2)) {  // LineFeed ??
26
        glcd.Cursor.x  = glcd.Window.x1;
27
        glcd.Cursor.y += FontHeight;
28
        if (glcd.Cursor.y + FontHeight > glcd.Window.y2) glcd.Cursor.y = glcd.Window.y1;
29
        flags |= 0x10;  // invalidate LCD address pointer
30
      }
31
      uint16_t bits;
32
      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
33
      uint8_t bitspixel = glcd.FontBitsPixel & 0x7F, bitsmask = 0xFF >> (8 - bitspixel), bitscount, RLE[4], charofs = glcd.FontLastChar - glcd.FontFirstChar;
34
      if (flags & 0x80) { // compressed Font ??
35
        data = glcd.FontData + (GLCD_FONT_HEADER_SIZE +1) + charofs;
36
        uint8_t padding = GLCD_READFUNC(data++);
37
        RLE[0] = 1;
38
        RLE[1] = GLCD_READFUNC(data++);
39
        RLE[2] = GLCD_READFUNC(data++);
40
        RLE[3] = GLCD_READFUNC(data++);
41
        uint32_t index = 0;
42
        for (i = glcd.FontFirstChar; i < c; i++) index += GLCD_READFUNC(data++);
43
        index *= padding;
44
        data = glcd.FontData + (GLCD_FONT_HEADER_SIZE +6) + (charofs *2) + index;
45
        bits = GLCD_READFUNC(data++);
46
        bitscount = 8;
47
      } else {
48
        data = glcd.FontData + GLCD_FONT_HEADER_SIZE;
49
        uint32_t index = 0;
50
        for (i = glcd.FontFirstChar; i < c; i++) index += GLCD_READFUNC(data++);
51
        index *= FontHeight * bitspixel;
52
        bitscount = index % 8;
53
        index /= 8;
54
        data = glcd.FontData + (GLCD_FONT_HEADER_SIZE +1) + charofs + index;
55
        bits = GLCD_READFUNC(data++) >> bitscount;
56
        bitscount = 8 - bitscount;
57
      }
58
      if (flags & 0x20) { // inialize LCD ??
59
        flags ^= 0x20;
60
        GLCD_CS_ON();
61
      #ifdef GLCD_ROTATE
62
        GLCD_SETMODE(0x37);
63
      #else
64
        GLCD_SETMODE(0x3F);
65
      #endif
66
        GLCD_SETCOMPARE(NONE);
67
      }
68
      if (flags & 0x10) { // LCD address pointer invalid ??
69
        flags ^= 0x10;
70
        GLCD_CS_PULSE();
71
      #ifdef GLCD_ROTATE
72
        GLCD_WINDOW(glcd.Cursor.y, glcd.Cursor.x, glcd.Cursor.y + FontHeight -1, GLCD_RIGHT);
73
        GLCD_SETADDR(glcd.Cursor.y, glcd.Cursor.x);
74
      #else
75
        GLCD_WINDOW(glcd.Cursor.x, glcd.Cursor.y, GLCD_RIGHT, glcd.Cursor.y + FontHeight -1);
76
        GLCD_SETADDR(glcd.Cursor.x, glcd.Cursor.y);
77
      #endif
78
        GLCD_STARTDATA();
79
      }
80
      glcd.Cursor.x += width;
81
      uint8_t leftwidth = 0;
82
      uint8_t rightwidth = width - charwidth;
83
      if (flags & 0x01) { // FixedFont ??
84
        leftwidth = rightwidth / 2;
85
        rightwidth -= leftwidth;
86
      }
87
      uint8_t ch,cl;
88
      ch = glcd.Colors[0] >> 8;
89
      cl = glcd.Colors[0] & 0xFF;
90
      for (; leftwidth > 0; leftwidth--) {
91
        for (i = FontHeight; i > 0; i--) {
92
          GLCD_WAIT();
93
          GLCD_OUT(ch);
94
          GLCD_WAIT();
95
          GLCD_OUT(cl);
96
        }
97
      }
98
      uint8_t pixelcount = 0;
99
      for (; charwidth > 0; charwidth--) {
100
        for (i = FontHeight; i > 0; i--) {
101
          if (!(pixelcount)) {
102
            pixelcount++;
103
            while (bitscount <= 8) {
104
              bits |= GLCD_READFUNC(data++) << bitscount;
105
              bitscount += 8;
106
            }
107
            if (flags & 0x80) { // compresed Font ??
108
              pixelcount = RLE[bits & 0x03];
109
              bits >>= 2;
110
              bitscount -= 2;
111
            }
112
            bitscount -= bitspixel;
113
            uint8_t j = bits & bitsmask;
114
            ch = glcd.Colors[j] >> 8;
115
            cl = glcd.Colors[j] & 0xFF;
116
            bits >>= bitspixel;
117
          }
118
          pixelcount--;
119
          GLCD_WAIT();
120
          GLCD_OUT(ch);
121
          GLCD_WAIT();
122
          GLCD_OUT(cl);
123
        }
124
      }
125
      ch = glcd.Colors[0] >> 8;
126
      cl = glcd.Colors[0] & 0xFF;
127
      for (; rightwidth > 0; rightwidth--) {
128
        for (i = FontHeight; i > 0; i--) {
129
          GLCD_WAIT();
130
          GLCD_OUT(ch);
131
          GLCD_WAIT();
132
          GLCD_OUT(cl);
133
        }
134
      }
135
      GLCD_WAIT();
136
    }
137
    if (!(flags & 0x20)) { // have LCD initialized, anything done ??
138
      GLCD_CS_PULSE();
139
      GLCD_RESETWINDOW();
140
      GLCD_SETMODE(0x30);
141
      GLCD_CS_OFF();
142
    }
143
}

Gruß Hagen

von Rolf Magnus (Gast)


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.

von Hagen (Gast)


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

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.