Forum: Mikrocontroller und Digitale Elektronik Variablen in ISR static - sinnvoll oder nicht?


von digitalWrite (Gast)


Lesenswert?

Macht es Sinn, in einer ISR (Timer, 250 Hz) die Vartiablen static zu 
deklarieren? Spart das dem µC die Arbeit, dieselben Variablen 250x pro 
Sekunde anzulegen, oder übersehe ich da was?

von Peter D. (peda)


Lesenswert?

digitalWrite schrieb:
> Spart das dem µC die Arbeit

Nein, es kostet CPU-Zeit, sie aus dem RAM zu holen, bzw. dort abzulegen.
Der Compiler würde lokale Variablen viel lieber nur in Registern anlegen 
wollen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

digitalWrite schrieb:
> Spart das dem µC die Arbeit, dieselben Variablen 250x pro
> Sekunde anzulegen, oder übersehe ich da was?

Im Gegenteil kostet das eher Arbeit, weil die Daten dann im RAM liegen 
und explizit zugegriffen werden müssen. Ohne "static" können lokale 
Variablen oft in Registern gehalten werden, was effizienter ist. Wenn 
viele Variablen benutzt werden, müssen sie auf den Stack gesichert 
werden, was in etwa genauso schnell ist wie bei "static"; allerdings 
kann man hier den maximalen Speicherbedarf besser einschätzen. 
Funktioniert natürlich nur wenn die ISR nicht re-entrant ist, was aber 
auf den meisten uC ohnehin nicht möglich ist.

von Michael U. (amiga)


Lesenswert?

Hallo,

das wird wohl stark von der Laune der GCC-Optimierung und dem 
Variablentyp abhängen. Er könnte z.B. eine Registervariable nutzen, wenn 
es nicht static ist, bei static muß er den Wert in jedem Fall irgendwo 
im Ram sichern.
Auch wenn ich im anderen Thread zu spät war: laß Dir das Listfile 
ausgeben und scheu rein, welchen ASM-Code er jeweils baut.
PS: nein, in der ArduinoIDE weiß ich nicht, wie man den Parameter setzt, 
noch nicht selbst gebraucht.

Jetzt reicht es mir aber, schon wieder zu spät... ;-)

Gruß aus berlin
Michael

: Bearbeitet durch User
von digitalWrite (Gast)


Lesenswert?

Peter D. schrieb:
> digitalWrite schrieb:
>> Spart das dem µC die Arbeit
>
> Nein, es kostet CPU-Zeit, sie aus dem RAM zu holen, bzw. dort abzulegen.
> Der Compiler würde lokale Variablen viel lieber nur in Registern anlegen
> wollen.

Hardware=Mega2560.
Hat es denn genügend Register? In der ISR gibt es ca. 10 Variablen.

Und wenn die ISR zu Ende ist, werden die Register doch wohl für andere 
Zwecke überschrieben. Ich kann dein Argument, sorry, also gerade nicht 
nachvollziehen.

von digitalWrite (Gast)


Lesenswert?

Michael U. schrieb:
> Jetzt reicht es mir aber, schon wieder zu spät... ;-)
:)

> Gruß aus berlin
> Michael

Gruß zurück

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

digitalWrite schrieb:
> Hat es denn genügend Register?

Immerhin 32.

digitalWrite schrieb:
> In der ISR gibt es ca. 10 Variablen.

Und welche Typen haben die?

digitalWrite schrieb:
> Und wenn die ISR zu Ende ist, werden die Register doch wohl für andere
> Zwecke überschrieben.
Ja. Sie werden beim Eintritt gesichert und beim Verlassen 
wiederhergestellt. Aber "static" Variablen müssen ja auch (temporär) in 
Registern abgelegt werden, weil die meisten uC (AVR inklusive) nicht 
direkt auf dem RAM rechnen können. Dadurch müssen die Register genauso 
gesichert werden. Der Unterschied zwischen lokal und "static" ist also, 
dass bei "static" die Werte vorher und nachher zusätzlich abgerufen 
bzw. gesichert werden.

von digitalWrite (Gast)


Lesenswert?

Niklas G. schrieb:

> Im Gegenteil kostet das eher Arbeit, weil die Daten dann im RAM liegen
> und explizit zugegriffen werden müssen. Ohne "static" können lokale
> Variablen oft in Registern gehalten werden, was effizienter ist. Wenn
> viele Variablen benutzt werden, müssen sie auf den Stack gesichert
> werden, was in etwa genauso schnell ist wie bei "static"; allerdings
> kann man hier den maximalen Speicherbedarf besser einschätzen.
> Funktioniert natürlich nur wenn die ISR nicht re-entrant ist, was aber
> auf den meisten uC ohnehin nicht möglich ist.

Ja das ist alles klar. Wir arbeiten ja letztendlich auf Assemblerhöhe.

Ich dachte auch eigentlich nur an das Allokieren. Variablen anlegen, 
löschen, anlegen, löschen ... usw. Bei static wäre das nur einmal der 
Fall. Dass Prozessor auf Variablen im RAM zugreifen muss, stört mich 
weniger als die Vorstellung permanenter Änderungen der RAM Struktur

von digitalWrite (Gast)


Lesenswert?

Niklas G. schrieb:

> Und welche Typen haben die?

alle byte (bzw. in Profisprech uint8_t ;) )

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

digitalWrite schrieb:
> Bei static wäre das nur einmal der
> Fall.

Nein. Der Prozessor kann nicht direkt auf dem RAM arbeiten 
(Load-Store-Architektur). Er muss die static-Variablen erstmal in 
temporäre unsichtbare Variablen (in Registern) übernehmen - d.h. es wird 
zusätzlich lokal Speicher allokiert.

Lokale Variablen sind oft nicht im RAM, da wird also nicht wirklich 
etwas allokiert. Register müssen nur ggf. vorher gesichert werden.

digitalWrite schrieb:
> alle byte (bzw. in Profisprech uint8_t ;) )
Dann passen die in Register. Es muss also gar kein Speicher auf dem 
Stack angefordert werden; nur zum Sichern der vorherigen Werte.

: Bearbeitet durch User
von digitalWrite (Gast)


Lesenswert?

Niklas G. schrieb:
> digitalWrite schrieb:
>> Bei static wäre das nur einmal der
>> Fall.
>
> Nein. Der Prozessor kann nicht direkt auf dem RAM arbeiten
> (Load-Store-Architektur). Er muss die static-Variablen erstmal in
> temporäre unsichtbare Variablen (in Registern) übernehmen - d.h. es wird
> zusätzlich lokal Speicher allokiert.

d.h. also, dass stativ Variablen Ihren Ort im Speicher ändern? Das kann 
ich mir eigentlich nicht vorstellen. Oder was habe ich falsch 
verstanden?


> Lokale Variablen sind oft nicht im RAM, da wird also nicht wirklich
> etwas allokiert. Register müssen nur ggf. vorher gesichert werden.

ja ähm, die Sicherung der Register bedeutet aber doch das Allokieren von 
Speicher (RAM).


> Es muss also gar kein Speicher auf dem
> Stack angefordert werden; nur zum Sichern der vorherigen Werte.

irgendwie beißt sich das, oder ich stehe wirklich am Schlauch

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

digitalWrite schrieb:
> d.h. also, dass stativ Variablen Ihren Ort im Speicher ändern?

Es wird eine lokale Kopie angelegt. Der AVR kann nicht direkt auf 
statische Variablen zugreifen.

Schau es dir im Assemblercode an bzw. versuche es selbst zu schreiben. 
Das macht alles klarer. Vor allem, wie sinnfrei es ist, statische 
Variablen zu laden und direkt zu überschreiben.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich verstehe die Frage noch nicht ganz. Die eigentliche Frage lautet 
doch, muss der Wert der lokalen Variable erhalten bleiben oder nicht. 
Danach wird entschieden ob diese static wird oder nicht.

von Axel S. (a-za-z0-9)


Lesenswert?

digitalWrite schrieb:
> Macht es Sinn, in einer ISR (Timer, 250 Hz) die Vartiablen static zu
> deklarieren?

Statische Variablen können in jeder Funktion und darum auch in einer ISR 
sinnvoll sein.

> Spart das dem µC die Arbeit

Das nicht. Aber der Grund, warum man lokale Variablen als static 
definiert ist ja ein logischer Grund und keine Optimierung. Man will, 
daß die Variablen ihren Wert zwischen Aufrufen der Funktion behalten.

von Cyblord -. (cyblord)


Lesenswert?

Veit D. schrieb:
> ich verstehe die Frage noch nicht ganz. Die eigentliche Frage lautet
> doch, muss der Wert der lokalen Variable erhalten bleiben oder nicht.
> Danach wird entschieden ob diese static wird oder nicht.

Richtig. Das ist was zählt.

Performance Überlegungen auf der hier bisher gemachten Ebene bringen in 
99% der Fälle gar nichts. Ausser schlechten Code und Bugs natürlich.

: Bearbeitet durch User
von digitalWrite (Gast)


Lesenswert?

Veit D. schrieb:
> Hallo,
>
> ich verstehe die Frage noch nicht ganz. Die eigentliche Frage lautet
> doch, muss der Wert der lokalen Variable erhalten bleiben oder nicht.
> Danach wird entschieden ob diese static wird oder nicht.

Ja, ich habe das wohl nicht verständlich geschrieben.

Statt static wären vielleicht auch globale Variablen ein Vergleich. In 
Funktionen, und die ISR ist ja auch eine, werden Variablen bei jedem 
Aufruf angelegt und nach dem Ende wird der Speicherplatz verworfen. Auch 
wenn das "nur" der Stack ist, ist hierzu Logistig nötig, und die kostet 
Zeit. Bei static wäre das meiner Ansicht nach nicht der Fall, und bei 
globalen Variablen auch nicht.

Und macht euch bitte nicht daran fest, dass Variablen in meinem Programm 
dauerhaft in Registern gehalten werden können. Das wird nicht der Fall 
sein, dazu sind es viel zu viele.

Vielleicht denke ich falsch, dass es vorteilhaft sein kann, wenn der 
Speicherort von Variablen im Speicher fest adressiert ist.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

digitalWrite schrieb:
> Bei static wäre das meiner Ansicht nach nicht der Fall, und bei
> globalen Variablen auch nicht.

Wie glaubst du denn erfolgt der Zugriff auf eine lokale oder statische 
Variable? Dazu sind immer Register erforderlich. Wofür eben genau die 
genannte Logistik gebraucht wird. Wenn du so etwas wie "++a" schreibst, 
und "a" ist statisch oder global und 1 Byte groß, macht der AVR-GCC 
daraus:
1. Adresse von "a" in ein Zeiger-Register-Paar laden (2x ldi)
2. Den Wert von "a" aus dem Speicher laden (ldr)
3. "a" inkrementieren (inc a)
4. "a" zurückspeichern (str)

Wenn a aber lokal ist, wird daraus nur ein "inc". Für die statische 
Variable sind sogar 2-3 Register erforderlich, die zuvor gesichert 
werden müssen ("Logistik"), für die lokale nur 1.

Schau es dir im Assembler-Code an statt Meinungen anzustellen...

von digitalWrite (Gast)


Lesenswert?

Axel S. schrieb:

> Das nicht. Aber der Grund, warum man lokale Variablen als /static/
> definiert ist ja ein logischer Grund und keine Optimierung. Man will,
> daß die Variablen ihren Wert zwischen Aufrufen der Funktion behalten.

Ja klar, ich weiß doch, wozu static normalerweise verwendet wird :-)

Die Frage ist vielleicht zu theoretisch. Ich versuche, mein Programme so 
zu gestalten, dass möglichst wenig Bewegung der Speicherstruktur da ist. 
Idealerweise soll alles seinen festen Platz haben. Ich bilde mir ein, 
dass das aus bestimmten Gründen vorteilhaft ist. Da bei der Allokierung 
lokaler Variablen der Stack genutzt wird, ist Fragmentierung zwar kein 
Problem, aber trotzdem müssen die Variablen beim Aufruf einer Funktion 
angelegt werden. Bei der ISR in meinem Fall 250x pro Sekunde. Aber 
vielleicht ist die Überlegung Kappes, und bei 16Mhz. wohl wirklich nur 
theoretisch.

von H.Joachim S. (crazyhorse)


Lesenswert?

Weiss nicht wie es beim GCC ist, aber bei CodeVision kann ich globale 
Variable in explizit in Registern anlegen.
Zugriff sehr schnell, fehlen dann natürlich im Rest des Programms. Da 
muss man dann schon genau abwägen, ob es Sinn macht.
In einer ISR kann es Sinn machen, wenn es um jeden Takt geht. 
Normalerweise braucht man sowas aber nicht.

uint8_t test @ 4;

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
test++;
}

_timer0_ovf_isr:
        ST   -Y,R30
        IN   R30,SREG
        INC  R4
        OUT  SREG,R30
        LD   R30,Y+
        RETI

von Einer K. (Gast)


Lesenswert?

digitalWrite schrieb:
> ja ähm, die Sicherung der Register bedeutet aber doch das Allokieren von
> Speicher (RAM).
Nein!
Für lokale Variabeln wird kein Speicher reserviert. Nix "Allokieren" von 
dynamischem Speicher und wieder freigeben.
Sie landen in Registern, oder auf dem Stack, wenn es zuviel wird.
Und ja, der Stackframe muss eingerichtet werden. Und das ist zur 
Laufzeit nur eine Addition, den Rest erledigt der Kompiler schon.


Grundsätzlich sind lokale Variablen zu bevorzugen, wenn man die Wahl 
hat.
Globale sind eher böse.
Globale belegen permanent RAM.
Lokale schlimmstenfalls Raum auf dem Stack.

von digitalWrite (Gast)


Lesenswert?

Niklas G. schrieb:

> Wie glaubst du denn erfolgt der Zugriff auf eine lokale oder statische
> Variable? Dazu sind immer Register erforderlich. Wofür eben genau die


Mein Gott noch mal! Jetzt hisse ich aber gleich die weiße Fahne. 
Natürlich müssen sie in Register geladen werden. Aber der Ort, von wo 
sie in Register geladen werden, ändert sich nicht andauernd. Und der Ort 
muss nicht 250x p.S. neu definiert werden.


Ich weiß nicht, wie ich es sonst schreiben soll.

von digitalWrite (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> digitalWrite schrieb:
>> ja ähm, die Sicherung der Register bedeutet aber doch das Allokieren von
>> Speicher (RAM).
> Nein!
> Für lokale Variabeln wird kein Speicher reserviert. Nix "Allokieren" von
> dynamischem Speicher und wieder freigeben.
> Sie landen in Registern, oder auf dem Stack, wenn es zuviel wird.
> Und ja, der Stackframe muss eingerichtet werden. Und das ist zur
> Laufzeit nur eine Addition, den Rest erledigt der Kompiler schon.
>
>
> Grundsätzlich sind lokale Variablen zu bevorzugen, wenn man die Wahl
> hat.
> Globale sind eher böse.
> Globale belegen permanent RAM.
> Lokale schlimmstenfalls Raum auf dem Stack.

Gut, sie müssen also nicht angelegt werden. Sind also nur ein Zeiger in 
den Stack. Leuchtet mir schon mal ein. Vielleicht denke ich bei 
"anlegen" noch zu viel auf Hochsprache-Niveau. Bei Assembler ist das ja 
nur eine Addition von benötigtem Speicherplatz und dem Verschie3ben des 
SP.

OK, danke.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

digitalWrite schrieb:
> Und der Ort
> muss nicht 250x p.S. neu definiert werden.

Der Ort wird bei lokalen Variablen nicht (nicht) bei jedem 
Interrupt-Eintritt neu angelegt. Die Variablen werden nur direkt in die 
Register gepackt. Falls sie doch auf den Stack gesichert werden - das 
Anlegen und Speichern geht mittels "Push"-Instruktion in einem 
Arbeitsgang und schneller als der Zugriff auf globale/statische 
Variablen.

von digitalWrite (Gast)


Lesenswert?

Gut, ok.

Mein Knoten im Gehirn beginnt sich aufzulösen.

Danke an alle :-)

von Michael U. (amiga)


Lesenswert?

Hallo,

digitalWrite schrieb:
> Mein Gott noch mal! Jetzt hisse ich aber gleich die weiße Fahne.
> Natürlich müssen sie in Register geladen werden. Aber der Ort, von wo
> sie in Register geladen werden, ändert sich nicht andauernd. Und der Ort
> muss nicht 250x p.S. neu definiert werden.

Du solltest mal Deine ISR zeigen oder ein Beipiel wie Du es meinst.

UINT8_t test = 8;
ist eine lokale Variable, die der Compiler als Registervariable bauen 
kann, also LDI regx,8;
Dazu braucht er keinen Ram. Wenn er ein Register braucht, kommt notfalls 
ein push regx; davor und ein pop regx; dahinter.

digitalRead(Port,Pin); muß sowieso mehr machen, weil der AVR keine IO 
auf Bitebene hat, nur ein paar Abfragen wie SBIS, SBIC. usw.
Lesen aus dem Ram muß sich die Adresse so oder so beschaffen und dann 
mit LDS o.ä. lesen. Ob er die Adresse da neu bestimmt oder eine gemerkte 
nutzt, macht auch keum Unterschied, auch die static-Adresse muß er erst 
irgendwo aus dem Ram beschaffen um dann von dort zu lesen.

Ich denke, Du denkst über die falsche Baustelle nach. 250x pro Sekunden 
sind 4ms Zykluszeit. Ein Takt bei 16MHz sind 62,5ns. Macht also rund 
64000 Zyklen für und zwischen den IRQ-Aufrufen. Da lohnt es nicht, über 
100 mehr oder weniger nachzudenken.

Gruß aus Berlin
Michael

von foobar (Gast)


Lesenswert?

> Da bei der Allokierung lokaler Variablen der Stack genutzt wird, ist
> Fragmentierung zwar kein Problem, aber trotzdem müssen die Variablen
> beim Aufruf einer Funktion angelegt werden.

Du kannst davon ausgehen, dass das Anlegen von lokalen Variablen 
kostenlos ist und immer die bevorzugte Variablenart sein sollte. Punkt.

von Theor (Gast)


Lesenswert?

digitalWrite schrieb:
> Axel S. schrieb:
>
>> [...]
Ich versuche, mein Programme so
> zu gestalten, dass möglichst wenig Bewegung der Speicherstruktur da ist.
> Idealerweise soll alles seinen festen Platz haben. Ich bilde mir ein,
> dass das aus bestimmten Gründen vorteilhaft ist. Da bei der Allokierung
> lokaler Variablen der Stack genutzt wird, ist Fragmentierung zwar kein
> Problem, aber trotzdem müssen die Variablen beim Aufruf einer Funktion
> angelegt werden. Bei der ISR in meinem Fall 250x pro Sekunde. Aber
> vielleicht ist die Überlegung Kappes, und bei 16Mhz. wohl wirklich nur
> theoretisch.

Die Frage ist durchaus nicht sinnlos. Allerdings spielen eine ganze 
Reihe von Faktoren eine Rolle, die sich gegenseitig, teilweise in dazu 
noch verschiedener Hinsicht, widersprechen und bei der ein Kompromiss 
gefunden werden musste, der sich in dem Compilerverhalten und dem 
Linkerverhalten, also in dem erzeugten Programm widerspiegelt.

Deswegen kann man nur empfehlen, sich irgendwann einmal mit der 
Assemblerprogrammierung und Compilerbau zu beschäftigen um zumindest 
eine Ahnung davon zu bekommen, was die Probleme sind.

In diesem Thread, ausgehend von Deiner ursprünglichen Frage, muss man 
klar so wie Axel S. antworten: Das die Möglichkeit der Beschreibung von 
Variablen als static zum einen den Grund hat, dass die Variable und die 
Funktion organisatorisch zusammen gehören und deswegen so beschrieben 
werden können und zum anderen. Zum anderen dass der Wert über mehrere 
Aufrufe hinweg erhalten bleibt.
Der letztere Grund würde eine Austauschbarkeit mit globalen Variablen 
erlauben, der erste hingegen nicht.


Ein Gesichtspunkt ist die Optimierung von Zugriffen auf diese Variable: 
Falls die Variable nur einmal in der Funktion überhaupt geschrieben 
oder gelesen wird, wäre es optimal, die Variable nicht in den Stack zu 
kopieren. Andernfalls aber wäre es optimal sie in den Stack zu kopieren.
Das gilt aber nur, falls die CPU auf Stackvariablen schneller zugreifen 
kann, als auf solche im RAM und zusätzlich, ob sie auf diese Variablen 
auch in arithmetischen und booleschen Befehlen zugreifen kann.
Der AVR z.B. kann arithmetische/boolesche Befehle ausschliesslich auf 
Register anwenden. In diesem Fall ist alleine eine Optimierung aufgrund 
der Frage ob einmal oder mehrmals auf die Variable zugegriffen wird, 
anwendbar.

Das ist nur ein Gesichtspunkt einer ganzen Reihe. Man kann die hier 
nicht alle erschöpfend beschreiben, diskutieren und gegeneinander 
abwägen. Das würde Jahre dauern.
Dazu gibt es eine Reihe von Texten im Internet und Büchern. 
Empfehlenswert ist z.B. das sogenannte "Drachenbuch" von Aho.
Da wird auch die Summe von falschen Vermutungen korrigiert, die Du hier 
beschrieben hast.


Effektiv gilt für den Hochsprachenprogrammierer: Dass Du Dich um 
Optimierung nicht kümmern solltest, es sei denn, es gibt einen absolut 
zwingenden Grund dafür. Und wenn dann zuerst um Optimierungen auf dem 
Level des Algorithmus. Hingegen nicht auf solche 
Hochsprachenformulierungen, die der Compiler in effizienteren Code 
umsetzen kann.
Ein Hauptgrund dafür ist, das solche Optimierungen eher marginale 
Wirkungen haben im Vergleich zu Optimierungen des Algorithmus.

Um ein Gefühl für Optimierung von Algorithmen zu bekommen, kann man sich 
mal die verschiedenen Varianten von Sortieralgorithmen ansehen. An sich 
ein Meilenstein jedes ernsthaften Programmierers, genau wie 
Kryptographie.

Falls es aber die genannten zwingenden Gründe gibt, ist es sinnvoll sich 
den Assemblertext anzusehen - wie hier auch schon empfohlen wurde. Und 
dazu muss man eben auch mal in Assembler programmiert haben.

von Axel S. (a-za-z0-9)


Lesenswert?

digitalWrite schrieb:
> Die Frage ist vielleicht zu theoretisch. Ich versuche, mein Programme so
> zu gestalten, dass möglichst wenig Bewegung der Speicherstruktur da ist.

Das ist falsch gedacht. Du machst hier gleich mehrere Fehler:

1. du triffst Annahmen darüber, wie der C-Compiler bestimmte Konstrukte 
umsetzt.

2. du glaubst, bestimmte Konstrukte wären vorteilhafter und ziehst sie 
deswegen vor.

3. Aber du machst dir nicht die Mühe, diese Annahmen auch mal zu 
überprüfen.

4. du optimierst an Stellen, bei denen das sehr wahrscheinlich gar keine 
Relevanz hat.

5. du opferst die Lesbarkeit des Codes einer (sogar nur vermeintlichen) 
Optimierung.


Das sind (entschuldige die klaren Worte) Anfängerfehler. Ein Profi 
schreibt Code (zumal in einer Hochsprache) zuerst mal

1. korrekt (der Code löst das Problem) und

2. lesbar (von einem Menschen nachvollziehbar und wartbar)

Optimierung kommt später. Und vor allem optimiert man nur das, was 
wirklich zu langsam ist.

: Bearbeitet durch User
von H.Joachim S. (crazyhorse)


Lesenswert?

Axel S. schrieb:
> Und vor allem optimiert man nur das, was
> wirklich zu langsam ist.

Oder zu gross (im Sinne von: es passt nicht mehr in den verfügbaren 
Speicher). Verkleinern um des Verkleinerns willen ist vertane Mühe.

von digitalWrite (Gast)


Lesenswert?

Axel S. schrieb:
> Das ist falsch gedacht. Du machst hier gleich mehrere Fehler:

> 1. du triffst Annahmen darüber, wie der C-Compiler bestimmte Konstrukte
> umsetzt.
> 2. du glaubst, bestimmte Konstrukte wären vorteilhafter und ziehst sie
> deswegen vor.
> 3. Aber du machst dir nicht die Mühe, diese Annahmen auch mal zu
> überprüfen.
> 4. du optimierst an Stellen, bei denen das sehr wahrscheinlich gar keine
> Relevanz hat.
> 5. du opferst die Lesbarkeit des Codes einer (sogar nur vermeintlichen)
> Optimierung.
>
> Das sind (entschuldige die klaren Worte) Anfängerfehler. Ein Profi
> schreibt Code (zumal in einer Hochsprache) zuerst mal

> Optimierung kommt später. Und vor allem optimiert man nur das, was
> wirklich zu langsam ist.

Klare Worte sind immer zu begrüßen. Umgesetzt habe ich von deinen 
Punkten 1 .. 5 allerdings nichts, entspanne dich also wieder. Ich 
handhabe die Optimierung schon, bevor ich die erste Zeile programmiert 
habe. Jedenfalls so weit das möglich ist (ein Spaziergang gehört zum 
Progranmmieren). Ein Kollege schreibt sich sogar die Zeit dafür auf und 
hat das vor der Kostenstelle auch durchgesetzt :-)

Nur sind deine Vermutungen falsch, ich habe noch gar nichts deoptimiert. 
Also alles in Butter.

von Oliver S. (oliverso)


Lesenswert?

Theor schrieb:
> Das ist nur ein Gesichtspunkt einer ganzen Reihe. Man kann die hier
> nicht alle erschöpfend beschreiben, diskutieren und gegeneinander
> abwägen. Das würde Jahre dauern.

Braucht man auch gar nicht, das haben die Compilerentwickler alles schon 
für uns getan. Der Compiler macht das schon.

Wenn dann Laufzeitprobleme auftreten, und ein Profiling ergibt, daß dies 
Probleme auf  die Zahl und verwendung lokaler und/oder statischer 
Variablen in der ISR zurüclzuführen ist, dann könnte man drüber 
nachdenken.
Vorher nicht.

Oliver

von digitalWrite (Gast)


Lesenswert?

Theor schrieb:
>
> Die Frage ist durchaus nicht sinnlos. Allerdings spielen eine ganze
> Reihe von Faktoren eine Rolle, die sich gegenseitig, teilweise in dazu
> noch verschiedener Hinsicht, widersprechen und bei der ein Kompromiss
> gefunden werden musste, der sich in dem Compilerverhalten und dem
> Linkerverhalten, also in dem erzeugten Programm widerspiegelt.
>
> Deswegen kann man nur empfehlen, sich irgendwann einmal mit der
> Assemblerprogrammierung und Compilerbau zu beschäftigen um zumindest
> eine Ahnung davon zu bekommen, was die Probleme sind.

Hast viel geschrieben, danke auch. Ich hatte bei der Frage wohl noch zu 
viel vom Speichermanagement von Hochsprachen im Kopf. Platz reservieren, 
Variable anlegen, nochmal Platz reservieren, Variable anlegen usw. (z.B. 
Basic Interpreter). Daher war die Frage unüberlegt bzw. ich 
betriebsblind oder auf der falschen Schiene, was Assembler und den Stack 
betrifft. Aber ist ja geklärt. Garantiert kommt mir meine Frage morgen 
genau so naiv vor wie euch heute :-)

von Peter D. (peda)


Lesenswert?

Lokale Variablen kann der Compiler immer am besten optimieren, z.B. kann 
er Variablen überlagern.
Man kann also der besseren Lesbarkeit wegen für Operand und Ergebnis 
verschiedene Variablen definieren und der Compiler hält sie aber im 
selben Register, wenn eine Variable nicht mehr gebraucht wird.

von Rainer V. (a_zip)


Lesenswert?

digitalWrite schrieb:
> Daher war die Frage unüberlegt bzw. ich
> betriebsblind oder auf der falschen Schiene, was Assembler und den Stack
> betrifft. Aber ist ja geklärt. Garantiert kommt mir meine Frage morgen
> genau so naiv vor wie euch heute :-)

Hallo, ich erlaube mir hier an dieser Stelle zu bemerken, dass du 
vielleicht auch mal deine ISR überdenken könntest. Eine ISR sollte 
(meist) so kurz wie möglich sein. D.h. man übergibt ein Flag oder einen 
Wert, der dann in der Hauptroutine entsprechend ausgewertet wird. Ein 
Progrämmchen mit 10 oder mehr Variablen gehört nmM. nicht in eine ISR!
Gruß Rainer

von Yalu X. (yalu) (Moderator)


Lesenswert?

digitalWrite schrieb:
> Hardware=Mega2560. Hat es denn genügend Register? In der ISR gibt es
> ca. 10 Variablen.

digitalWrite schrieb:
> alle byte (bzw. in Profisprech uint8_t ;) )

Mit dem AVR-GCC stehen insgesamt 30 Datenregister (R2 bis R31) für
lokale Variablen zu Verfügung. Für deine 10 uint8_t-Variablen reicht das
also locker.

Natürlich muss jedes Register vor seiner Benutzung auf den Stack gepusht
und hinterher wieder zurückgepoppt werden. Werden die Variablen
stattdessen statisch im RAM abgelegt wird jede ebenfalls mindestens
einmal geschrieben und gelesen, was gleich viel Zeit kostet. Wird auf
eine Variable mehr als zweimal zugegriffen, ist der Weg über statische
Variablen sogar langsamer.

So weit kommt es aber meistens gar nicht: Wenn der Compiler erkennt,
dass die Inhalte einer static-Variable nicht zwischen zwei ISR-Aufrufen
aufbewahrt werden muss (das ist immer dann der Fall, wenn der erste
Zugriff auf die Variable innerhalb der ISR ein Schreibzugriff ist), dann
optimiert er die Variable weg. Der generierte Code ist dann praktisch
derselbe, wie wenn du das "static" weggelassen hättest.

digitalWrite schrieb:
> Spart das dem µC die Arbeit, dieselben Variablen 250x pro Sekunde
> anzulegen, oder übersehe ich da was?

Das "Anlegen" der automatischen Variablen besteht normalerweise aus 1
PUSH und 1 POP (zusammen 4 Zyklen) pro Variable für die Sicherung auf
dem Stack. Wenn für die Variablen mehr als 30 Byte benötigt werden, wird
für diejenigen, die nicht in Registern gehalten werden können, Platz auf
dem Stack reserviert und am Ende der ISR wieder freigegeben. Das dauert
für alle Variablen zusammen – unabhängig von deren Anzahl – 10 Zyklen.
Ein PUSH und POP ist für die auf dem Stack gehaltenen Variablen nicht
erforderlich, dafür dauern Schreib- und Lesezugriffe länger, weil sie im
RAM liegen.

Eine Variable nur aus Optimierungsgründen static zu machen, bringt also
höchstens dann etwas, wenn alle lokalen Variablen in einer ISR den
Rahmen von 30 Byte sprengen, und selbst dann ist der prozentuale
Zeitgewinn so gering, dass gerne darauf verzichtet (alleine die dann
erforderlichen PUSHs und POPS aller Register dauern schon 128 Zyklen, so
dass die 10 Zyklen für die Stackreservierung kaum ins Gewicht fallen).

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.