Georg M. schrieb:>> Zielplattform>> 8-Bit AVR mit 16-Bit TCB
Na mit dieser Fülle an Informationen kann man sicherlich sagen:
Schnelleren Controller nehmen hilft.
Georg M. schrieb:> Aber geht es auch schneller?
Wie definierst du "schnell"? Wie sieht der aus diesem Code erzeugte
Assembler aus? Wie ist p definiert und wie t? Welchen Optimierungslevel
hast du eingeschaltet?
> if(p[i+1] < p[i] + t && p[i+1] > p[i] - t)
Ist diese if-Abfrage Teil einer Schleife mit ansteigendem i? Dann könnte
man sich sparen, laufend immer wieder p[i] einzulesen, wenn man zuvor
schon p[i+1] eingelesen hat. Zeig mal mehr vom Code.
> Aber geht es auch schneller?
Was ist "es", was willst du überhaupt machen?
aber das benötigt auch 2 Vergleiche und ist damit genau so disruptiv,
hoffentlich hat der Prozessor gute branch prediction.
Wenn der Prozessor Multiplikation in einem Takt schafft ist
1
(p[i+1]-p[i])^2<tsquared
eventuell schneller.
Kommt also immer auf die Hardware an.
Natürlich ist der indiziere Zugriff auf p optimierbar, aber das sollte
der Compiler schaffen. Er wird auch die 2 Zugriffe pro Wert in deinem
Original wohl durch Register optimieren, wenn der Prozessor davon
genügende hat.
Michael B. schrieb:> Natürlich ist der indiziere Zugriff auf p optimierbar, aber das sollte> der Compiler schaffen.
Wenn da nicht noch irgendwie "zur Sicherheit, weil das ja in einer ISR
verwendet wird" ein volatile davor steht.
Also Fazit: mehr vom Code zeigen (am besten in einem compilierbaren
"Dreizeiler") und den erzeugten Assembler anschauen.
Michael B. schrieb:> Kommt also immer auf die Hardware an.
Ist bekannt:
>> Zielplattform> 8-Bit AVR mit 16-Bit TCB
Lothar M. schrieb:> Was ist "es", was willst du überhaupt machen?
Es geht mir primär nur um diese eine Zeile, ob sie irgendwie
umgeschrieben werden kann, so dass das Ausführen schneller abläuft, auch
wenn sich dadurch die Lesbarkeit des Codes verschlechtert.
Und wenn nicht, dann nicht. Dann bin ich beruhigt.
Georg M. schrieb:> Es geht mir primär nur um diese eine Zeile, ob sie irgendwie> umgeschrieben werden kann, so dass das Ausführen schneller abläuft, auch> wenn sich dadurch die Lesbarkeit des Codes verschlechtert.
Im Zweifelsfall kannst du direkt Assembler in den Code packen.
Bestimmt ist es überflüssig, sich jedes mal 4 Werte zu holen. Woher
kommt t. Kann sich der ändern oder darf der vor dem Compiler auf einen
festen Wert gesetzt werden?
Georg M. schrieb:> Es geht mir primär nur um diese eine Zeile
Optimieren kann man das nur, wenn man mehr sieht.
- Ist eine Schleife drumherum?
- Wenn ja, ist p[i] der letzte Wert von p[i+1]? (Zwischenvariable)
- Wird p[i] - t und p[i] + t mehrfach gebraucht? (Register)
- Trifft öfter Bedingung 1 oder Bed. 2 zu? (short-circuit evaluation)
- Von welchem Typ sind p und i? (Array vs. Pointer)
- Ist t konstant? (Lookuptabellen)
Es gibt jede Menge möglicher Optimierungen, wenn man mehr drumherum
sieht. Aber das scheint ja geheim zu sein.
Könnte sein, dass Loop-Unrolling was bringt, da dann aus p[i] eine feste
Adresse wird.
Eventuell bringt schon das Arbeiten mit einem Pointer, der in der
Schleife weiter geschoben (äh inkrementiert) wird, was. Beim Zugriff auf
p[i], muss der Compiler ja den Wert von i mit der Größe eines Elements
des Arrays multiplizieren.
Georg M. schrieb:> Es geht mir primär nur um diese eine Zeile, ob sie irgendwie> umgeschrieben werden kann, so dass das Ausführen schneller abläuft
1
if(p[i+1]<p[i]+t&&p[i+1]>p[i]-t)
Ach so. Na dann ist es einfach. Mach einfach vor dem && einen
Zeilenumbruch. Dann läuft deine Zeile gleich doppelt so schnell.
"Tä-tä, tä-tä, tä-tä!" - "Wolle mer 'n rein lasse?"
Und jetzt mal ernst: kein Schwein versteht deinen Code nur vom Ansehen
dieses einen Codeschnipsels. Ich vermute mal in p[] stehen irgend welche
Samplewerte? Aber was soll t da im Vergleich?
Georg M. schrieb:> Dann bin ich beruhigt.
Wenn das der einzige Grund für die Optimierung ist solltest du sie
lassen.
Optimieren nur wenn es notwendig ist
In über 90% der Fälle geht Übersichtlichkeit vor einem kleinen
Performancegewinn.
Außer bei Cloud systeme spart man nix, wenn der Prozessor nur 5% statt
6% Auslastung hat.
Georg M. schrieb:> Es geht mir primär nur um diese eine Zeile, ob sie irgendwie> umgeschrieben werden kann
Das geht nur in seltenen Einzelfällen. Die Compiler optimieren die
einzelnen Schritte schon sehr gut. Nur wenn man das Gesamtbild
betrachtet kann man schon mal "Synergien" finden. Also z.B. Werte über
mehrere Schleifendurchläufe wieder verwenden/durchreichen, anderen
Algorithmus wählen, smartere Datenstruktur nutzen etc.
Bei größeren Controllern (z.B. Cortex-M4/7) geht manchmal was durch
Nutzung von SIMD-Instruktionen.
Frank M. schrieb:> Wird p[i] - t und p[i] + t mehrfach gebraucht? (Register)Flunder schrieb:> Eventuell bringt schon das Arbeiten mit einem Pointer, der in der> Schleife weiter geschoben (äh inkrementiert) wird, was
Diese Dinge kriegen die Compiler tatsächlich meist schon selbst gut hin.
Udo S. schrieb:> Außer bei Cloud systeme spart man nix, wenn der Prozessor nur 5% statt> 6% Auslastung hat.
Bei Ultra-Low-Power Anwendungen kann das eventuell was bringen, wenn die
Schleife wirklich dominant beim Energieverbrauch ist, und man vorher
schon alles andere optimiert hat (Sleep Modi, CPU-Takt etc).
Michael B. schrieb:> Wenn der Prozessor Multiplikation in einem Takt schafft ist> (p[i+1]-p[i])^2<tsquared> eventuell schneller.
^ ist die xor Operation...
Georg M. schrieb:> Es geht mir primär nur um diese eine Zeile, ob sie irgendwie> umgeschrieben werden kann, so dass das Ausführen schneller abläuft, auch> wenn sich dadurch die Lesbarkeit des Codes verschlechtert.
Lass das mal besser den Compiler machen. Der kann auf Maschinenebene
optimieren. Da muss man nicht extra den ASCII-Code umsortieren, dass der
kapiert, was man selber so meint, dass grade optimal wäre, sondern es
reicht, ihm mitzuteilen, dass sich die verwendeten Variablen während des
Programmablaufs nicht ändern können.
Es kommt eben wie gesagt darauf an, woher die zu vergleichenden
Variabeln kommen und ob man sie in einem lokalen Register
zwischenspeichern kann. Und dann kommt es eben auch noch drauf an, ob in
der {} das Pointerregister auch noch gebraucht wird und wieder neu
geladen werden muss usw. usf.
Evtl. ist aber schon die Abfrage Käse, wenn das unsigned TCNT-Register
in den Bereich des Überlaufs kommt und man müsste gegen solche
Überlaufprobleme sowieso den Code umschreiben (und dabei die richtigen
Datentypen signed/unsigned nehmen):
1
if(p[i+1]<p[i]+t&&p[i+1]>p[i]-t)
2
-->
3
if(p[i+1]-p[i]<t&&p[i+1]-p[i]>-t)
Dann hättte man nur 1x die Rechnung p[i+1] - p[i]. Aber auch diese
einfache Formelumstellung traue ich dem Optimierer inzwischen zu.
Wichtiger als Geschwindigkeit ist Lesbarkeit und „es nicht zu
verdaddeln“. Selbst auf kleinstem Prozessor nutze ich dafür eine Routine
(nicht „inrange“ sondern between).
Verdaddeln wäre: volatile, Makro-Doppelauswertung, signed/unsigned,
integral promotion, unsigned-Unterlauf, Und selbst dabei fahre ich oft
harakiri und fange den signed-überlauf nicht korrekt ab, bzw. überlasse
das der statistischen Codeanalyse
Axel S. schrieb:> Und jetzt mal ernst: kein Schwein versteht deinen Code nur vom Ansehen> dieses einen Codeschnipsels. Ich vermute mal in p[] stehen irgend welche> Samplewerte? Aber was soll t da im Vergleich?
DU verstehst es nicht.
Alleine schon der Kommentar "// t: tolerance" hilft.
Niklas G. schrieb:> Die Compiler optimieren die einzelnen Schritte schon sehr gut
Du glaubst immer noch das Märchen 9
Daniel A. schrieb:> ^ ist die xor Operation...
Nennt man Mathematik, verstehst du nichts von.