Forum: Mikrocontroller und Digitale Elektronik Arduino Uno: Optimiert der Compiler sich im Loop wiederholende Befehle?


von Hustle (Gast)


Lesenswert?

Arduino Uno:

Überlicherweise intitialisiert man den Wert einer unveränderlichen 
Variable gleich in der Delaration:
1
int variable = 15;

Ich möchte die Variable aus Gründen der Übersicht dort im Programmtext 
setzen, wo sie auch eingesetzt wird. Dies auch deswegen, weil für 
jedesmal, wo eine bestimmte Funktion im Programm benötigt wird ein 
Programmblock in den loop Teil kopiert und die Werte der Variablen für 
die jeweilige Anforderung spezifiziert werden müssen. Die näheren 
Umstände für diese Notwendigeit werde ich in einem anderen Posting 
diskutieren. Dazu gehört auch die oben genannte unveränderliche 
Variable. Wenn ich diese Variable in der Deklaration initialisiere, wäre 
das Kilometer weit weg und von daher unübersichtlich.

Jetzt meine Fragen: Die Zuweisung der nicht variablen Variable
1
variable = 15;
würde bei jedem Durchlauf des loop stattfinden, ohne dass sich der Wert 
an anderer Stelle verändert.

Frage 1) Ist der Arduino Compiler intelligent genug, das zu erkennen und 
die Zuweisung nur einmal vorzunehmen?

Frage 2) Ist er sogar intelligent genug, die Variable im Flash statt im 
RAM zu speichern?

von (prx) A. K. (prx)


Lesenswert?

Hustle schrieb:

> Frage 1) Ist der Arduino Compiler intelligent genug, das zu erkennen und
> die Zuweisung nur einmal vorzunehmen?

Der GCC ist bei Optimierung recht gut aufgestellt.

> Frage 2) Ist er sogar intelligent genug, die Variable im Flash statt im
> RAM zu speichern?

Er ist intelligent genug, Variablen ganz wegzulassen oder 
ausschliesslich in Registern zu halten, wenn der Rest des Programms dem 
nicht entgegen steht.

Allerdings ist für wirklich qualifizierte Antworten deine Frage zu vage. 
Programmstücke beschreibt man nicht in Prosa, sondern in Code.

von Einer K. (Gast)


Lesenswert?

Hustle schrieb:
> Überlicherweise intitialisiert man den Wert einer unveränderlichen
> Variable gleich in der Delaration:
> int variable = 15;

Eine unveränderliche Variable, nennt sich Konstante.

Also wäre eher:
> const int bezeichner = 15;
eine angemessene Ausformulierung

Das Const kennzeichnet das Element als "read only".
Das verhindert ungewollte Veränderungen, bzw. schreit der Compiler, wenn 
er bemerkt, dass du das versuchst.

Auch erlaubt das const setzen, dem Compiler weitergehende Optimierungen. 
Soweit wie möglich, wird der Kompiler kein RAM für eine solche Konstante 
reservieren, sondern den Wert direkt in den generierten Code 
einflechten.
In dem Fall ist es natürlich egal wo die die Definition/Deklaration hin 
schreibst.


-------------

Hustle schrieb:
> Ich möchte die Variable aus Gründen der Übersicht dort im Programmtext
> setzen, wo sie auch eingesetzt wird. Dies auch deswegen, weil für
> jedesmal, wo eine bestimmte Funktion im Programm benötigt wird ein
> Programmblock in den loop Teil kopiert und die Werte der Variablen für
> die jeweilige Anforderung spezifiziert werden müssen. Die näheren
> Umstände für diese Notwendigeit werde ich in einem anderen Posting
> diskutieren. Dazu gehört auch die oben genannte unveränderliche
> Variable. Wenn ich diese Variable in der Deklaration initialisiere, wäre
> das Kilometer weit weg und von daher unübersichtlich.

Das verstehe ich nicht.

Möchtest du lokale Konstanten erzeugen?
Auch für diese kann man sagen, dass der Kompiler das möglichst weit 
optimiert.

Was da wirklich mit passiert, muss man sich wohl im erzeugten Code 
anschauen.


Tipp:
Nicht so sehr um Microoptimierungen kümmern, sondern eher darum, dass 
der Code übersichtlich bleibt/wird.

von Dr. Sommer (Gast)


Lesenswert?

Ist das eine globale Variable, welche innerhalb der Schleife vor einem 
Funktionsaufruf gesetzt wird? Dann kann der Compiler das nicht 
optimieren, da er nicht weiß ob der Funktionsaufruf die Variable nicht 
verändert hat; es sei denn die Funktion und alle davon aufgerufenen 
stehen in der selben Datei.

Letztlich kostet so ein Zugriff eh nur ein paar Takte. Klarheit bringt 
es, sich den disassemblisierten Code anzusehen.

von Hustle (Gast)


Lesenswert?

A. K. schrieb:
> Allerdings ist für wirklich qualifizierte Antworten deine Frage zu vage.
> Programmstücke beschreibt man nicht in Prosa, sondern in Code.

Okay. Hier ein zur Beurteilung der Optimierung auf das Wesentliche 
konstruiertes Programm. Hier würde in jedem Loop Durchlauf die gleiche 
Zuweisung stattfinden. Variable und eine Wertzuweisung sind im 
Programmtext unentbehrlich, da der Wert später zweimal gebraucht wird. 
Das auszugebende Ergebnis lässt sich zur Compilerzeit nicht 
vorausberechnen, da ADC erst zur Laufzeit bekannt wird. Sinnvoll 
bezüglich der Optimierung wäre die sich nicht wiederholende Zuweisung in 
jedem Loop.
1
int variable, ADC;
2
3
void setup() {
4
  Serial.begin(9600);
5
}
6
7
void loop() {
8
variable = 15; // Das ist der sich in jedem Loop wiederholende Befehl
9
// Lese über SPI Ergebnis vom ADC Wandler ein und speichere in "ADC"
10
Serial.print(variable * ADC);
11
Serial.print(variable + ADC);
12
}

von Einer K. (Gast)


Lesenswert?

1
// ein recht guter Platz, für eine Konstante
2
const int konstante = 15;
3
4
5
void setup() {
6
  Serial.begin(9600);
7
}
8
9
void loop() 
10
{
11
  int ADC;
12
  // hier Lese über SPI Ergebnis vom ADC Wandler ein und speichere in "ADC"
13
  Serial.print(konstante * ADC);
14
  Serial.print(konstante + ADC);
15
}


-------------------------------------

1
void setup() {
2
  Serial.begin(9600);
3
}
4
5
void loop() 
6
{
7
  int ADC;
8
  const int konstante = 15; // ungünstig, eine magische Zahl mitten im Code
9
  // hier Lese über SPI Ergebnis vom ADC Wandler ein und speichere in "ADC"
10
  Serial.print(konstante * ADC);
11
  Serial.print(konstante + ADC);
12
}

von (prx) A. K. (prx)


Lesenswert?

Hustle schrieb:
> void loop() {
> variable = 15; // Das ist der sich in jedem Loop wiederholende Befehl
> // Lese über SPI Ergebnis vom ADC Wandler ein und speichere in "ADC"
> Serial.print(variable * ADC);
> Serial.print(variable + ADC);
> }

So wird es formal jedes mal neu initialisiert, aber wahrscheinlich 
wegoptimiert.

Wenn es nur einmal sein soll, dann:
1
void loop() {
2
  static int variable = 15; // Das ist der sich in jedem Loop wiederholende Befehl
3
  // Lese über SPI Ergebnis vom ADC Wandler ein und speichere in "ADC"
4
  Serial.print(variable * ADC);
5
  Serial.print(variable + ADC);
6
}

: Bearbeitet durch User
von Experte (Gast)


Lesenswert?

Hustle schrieb:
>        int variable, ADC;
>
>        void lese_spi() {
>          ADC = ...;
>        }
>
>        void loop() {
>  (1)     variable = 15;
>  (2)     lese_spi();
>  (3)     Serial.print(variable * ADC);
>  (4)     Serial.print(variable + ADC);
>        }

Globale Variablen sind immer Mist. In vielerlei Hinsicht. Nicht nur 
ist es sehr schlechter Programmierstiel, auch werden viele Optimierungen 
verhindert.

Der Grund? Mögliche Schreib-Zugriffe aus anderen Funktionen!

Dein Beispiel ist noch viel schlechter, als Du Dir im Moment vorstellst. 
Grundsätzlich gilt bei solchen Sachen immer, wenn man sich unsicher ist: 
Nachschauen/Ausprobieren/Messen. D.h. schau Dir das Assembler-Listing 
verschiedenere Varianten an und lerne. So kommst Du vorwärts.

Zurück zum Problem.

 a.) Zeile (1) kann nicht wegoptimiert werden, da 'variable'
     global ist und z.B. jederzeit von anderen Funktionen
     geschrieben und/oder gelesen werden kann.

 b.) In Zeile (3) muss der Compiler die Variablen 'ADC' und
     'variable' neu lesen, weil beide globalen Variablen
      möglicherweise in 'lese_spi()' verändert wurden!

 c.) In Zeile (4) wieder das gleiche. Der Compiler weiß nicht,
     welche globalen Variablen in der Methode 'Serial.print()'
     verändert wurden, also muss er hier wieder beide Variablen
     'ADC' und 'variable' erneut lesen.

Bei globalen Variablen kann der Compiler praktisch kaum optimieren!


So wie es "Arduino Fanboy D. (ufuf)" vorgeschlagen hat, ist es richtig:
1
const int konstante = 15;
2
3
void loop() 
4
{
5
  int ADC = lese_adc_mit_spi_ein();
6
  Serial.print(konstante * ADC);
7
  Serial.print(konstante + ADC);
8
}

von Thomas E. (thomase)


Lesenswert?

Experte schrieb:
> Globale Variablen sind immer Mist.

Du erzählst immer Mist.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

A. K. schrieb:
> Der GCC ist bei Optimierung recht gut aufgestellt.
> Er ist intelligent genug, Variablen ganz wegzulassen

offensichtlich, man unterschätzt die Fähigkeiten!

Ich habe gerade wieder ein Putz- & Aufräumphase in meinem Code, da fiel 
mir eine ungenutzte uint32_t Var. auf.
Ich löschte diese und erwartete 4 freie Bytes mehr, Pustekuchen, der gcc 
hatte sie wohl schon ignoriert oder rausgeworfen!

: Bearbeitet durch User
von Hustle (Gast)


Lesenswert?

Experte schrieb:
>>        void lese_spi()

Könntest Du davon ausgehen, dass das Einlesen des ADC nicht durch eine 
Funktion, sondern explizit programmiert an der Stelle
1
// Lese über SPI Ergebnis vom ADC Wandler ein und speichere in "ADC"
durchgeführt wird und dann eine Neubewertung der Optimierung vornehmen? 
Ansonsten beantwortet sich meine Ursprungsfrage nicht.

Ich weiß, dass alles schlechter Programmierstil ist. Aber ich habe das 
extra (schlecht) konstruiert, um die Frage nach der Wegoptimierung sich 
im loop wiederholender Zuweisungen zu klären. Wenn jetzt der 
Funktionsaufruf diese Optimierung verhindert, soll das Einlesen ohne 
Funktionsaufruf sondern durch explizite Programmierung erfolgen.

Arduino Fanboy D. schrieb:
> // ungünstig, eine magische Zahl mitten im Code

Das originale Programm ist komplexer und bedarf Kenntnisse von PLCs. Da 
hätte die Diskussion im Forum um das originale Programm die eigentliche 
Fragestellung der Optimierung in den Hintergrund gestellt. Deshalb soll 
der konstruierte Code das Problem isolieren. Diese Isolation konnte ich 
ohne schlechte Programmierung nicht hinbekommen.

Experte schrieb:
> D.h. schau Dir das Assembler-Listing
> verschiedenere Varianten an und lerne.

Gutes Stichwort! Wo in der Arduino Software kann ich den Assembler 
sehen?

von Dr. Sommer (Gast)


Lesenswert?

Hustle schrieb:
> Wenn jetzt der
> Funktionsaufruf diese Optimierung verhindert, soll das Einlesen ohne
> Funktionsaufruf sondern durch explizite Programmierung erfolgen.

Der Funktionsaufruf an sich ist wahrscheinlich schon langsamer als diese 
Zuweisung. Arduino ist sowieso nicht besonders effizient. Da willst du 
wegen dieser 2-3 Takte das Programm schlechter lesbar machen?

Hustle schrieb:
> Gutes Stichwort! Wo in der Arduino Software kann ich den Assembler
> sehen?

https://ucexperiment.wordpress.com/2012/02/21/arduino-assembly-language-listing-of-compiled-sketch-windows/

von Einer K. (Gast)


Lesenswert?

Hustle schrieb:
> Experte schrieb:
>> D.h. schau Dir das Assembler-Listing
>> verschiedenere Varianten an und lerne.
>
> Gutes Stichwort! Wo in der Arduino Software kann ich den Assembler
> sehen?

Das gibts so noch nicht, muss man in die Arduino IDE einbauen
Hier habe ich mal gezeigt, wie es geht:
Beitrag "Re: Welche Ressourcen nutzt die Arduino Software?"

von Kolja L. (kolja82)


Lesenswert?

Thomas E. schrieb:
> Experte schrieb:
>> Globale Variablen sind immer Mist.
>
> Du erzählst immer Mist

Mindestens einer von euch beiden lügt.

von Programmier Schüler (Gast)


Lesenswert?

Hallo

"Eine unveränderliche Variable, nennt sich Konstante.
...
Das Const kennzeichnet das Element als "read only".
Das verhindert ungewollte Veränderungen, bzw. schreit der Compiler, wenn
er bemerkt, dass du das versuchst.
Auch erlaubt das const setzen, dem Compiler weitergehende Optimierungen.
Soweit wie möglich, wird der Kompiler kein RAM für eine solche Konstante
reservieren, sondern den Wert direkt in den generierten Code
einflechten.
In dem Fall ist es natürlich egal wo die die Definition/Deklaration hin
schreibst."

Eine schöne Erklärung, die für Leute wie mich welche durchaus vertieftes 
Wissen über die Hardware allgemein und den Grundlegenden Hardwareablauf 
in einen µC und was generell mit erstellten Code "gemacht" wird bis er 
als hex Datei in den µC geladen wird haben, aber nur wenig bis überhaupt 
keine über die eigentlich Programmierung (in meinen Fall hatte) sehr 
verständlich ist und so manche irgendwann ergebende Frage zu den warum 
und wann bezüglich Konstanten und auch teilweise Variablen schon im 
Voraus verhindert.
Was eine Konstante generell ist, ist einen (hoffentlich) noch aus den 
Mathematikunterricht bekannt aber das genau warum und wie von Konstanten 
in der µC Programmierung wird nur selten wirklich so klar und leicht 
verständlich erklärt wie jetzt von dir.
Leider scheinen alle C, C++ und "Arduinoprogrammiertutorials" davon 
auszugehen das man in der Programmierung schon vertiefte Grundkenntnisse 
hat aber bezüglich der Hardware ein absoluter Anfänger ist.

Schade das es für Leute mit meinen (damaligen) Voraussetzungen kaum 
Literatur und auch nur sehr wenig im Netz gibt und mann die wirklich 
guten Erklärungen nur zufällig in Forenbeträgen oder manchmal halt recht 
gut "versteckt" in irgendein Tutorial oder Buch findet.

Programmier Schüler

von Peter D. (peda)


Lesenswert?

Ich schaue mir auch oft das Listing an. Manches optimiert der AVR-GCC 
extrem clever, manchmal stellt er sich aber auch strunzdumm an.

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.