Forum: Mikrocontroller und Digitale Elektronik Perfomancevorteil - Algorithmus


von Lens (Gast)


Lesenswert?

Hi,

Folgender Code soll perfomant sein. Es geht um einen Ringpuffer bei der 
seriellen Kommunikation (die Arraygröße ist eine Zweierpotenz): Ich 
finde es ist sehr schlecht lesbar:
1
if (((r_in - r_out) & ~(RBUF_SIZE-1)) == 0)
2
{
3
 rbuf [r_in & (RBUF_SIZE-1)] = SBUF;
4
 r_in++;
5
}

Ich hingegen hätte einfach nur geschrieben:
1
if(r_in >= RBUF_SIZE)
2
 r_in = 0;
3
4
rbuf[r_in++] = SBUF;

Ist doch das gleiche oder? Mir ist auch klar, dass man bei solchen 
Anwendungen möglichst viel effizienten Code schreiben muss, um eine 
geschmeidige Kommunikation zu ermöglichen.

von fußnagel (Gast)


Lesenswert?

So wird es noch geschmeidiger:
http://www.duden.de/rechtschreibung/performant

von Lens (Gast)


Lesenswert?

Was hast du denn für einen Namen :)

von Leser (Gast)


Lesenswert?

Lens schrieb:
> if(r_in >= RBUF_SIZE)
>  r_in = 0;

Und wo bleiben da die konstante Laufzeit und das Überholverbot?

von Fritz (Gast)


Lesenswert?

Die beiden Codestücke sind nicht gleichwertig in der Funktion.
Im ersten wird mit der if Abfrage der Bufferzustand überprüft, während 
im 2. Codesegment nur die Bufferinkrementierung behandelt wird.

Man muß als nur die 2 Zeilen innerhald des if des 1. Codebeispiel mit 
den 2. Codebeispiel vergleichen.

Vor- und Nachteile:

Codestück 1: Wird i.A. auf den schnellsten Code hinauslaufen. Wird ein 
bitweises AND und ein INCREMENT im Assemblercode ergeben (also 2 
Assemblerbefehle).
Nachteil: funktioniert nur mit 2-er Potenz langen Buffern.

Codestück 2: funktioniert mit jeder Buffergröße. Erfordert im 
Assemblercode (je nach Architektur) einen bedingten Sprung oder bedingte 
Assembleranweisungen, was nur wenige Assembler-Architekturen können. Der 
Bedingte Sprung hat auch so manche Nachteile weil er (je nach Processor) 
ein Pipeline leeren und neu füllen erfordern kann. Aber auch mit den 
besten Architekturen wird man kaum schneller als Variante 1 sein.
Mag auf den 1. Blick in C besser verständlich sein.

von Lens (Gast)


Lesenswert?

Moin,

erstmal danke für die Antwort. Ich hätt eher gedacht, dass es mehr als 
ein "AND" und ein "INCREMENT" ist in Variante-1. Man hat ja schließlich 
ein "AND", "NOT" und dann auch noch ein Vergleich mit 0 in "if" und dann 
nochmal die Indexberechnung mit "AND" und dann nochmal Inkrement.

Das ist ja auch nicht wenig. Aber wahrscheinlich sind dann halt diese 
Operationen auf Binärebene schneller.

von (prx) A. K. (prx)


Lesenswert?

Die beiden Häppchen haben völlig unterschiedliches Verhalten beim 
Überlauf des Puffers, also bei mehr Daten als der Puffer fassen kann. 
Das erste verwirft die überschüssigen Daten, beim zweiten gehen 
komplette Pufferinhalte verloren, weil die entscheidende Relation 
zwischen r_in und r_out nicht beachtet wird.

von Fritz (Gast)


Lesenswert?

Lens schrieb:
> erstmal danke für die Antwort. Ich hätt eher gedacht, dass es mehr als
> ein "AND" und ein "INCREMENT" ist in Variante-1. Man hat ja schließlich
> ein "AND", "NOT" und dann auch noch ein Vergleich mit 0 in "if" und dann
> nochmal die Indexberechnung mit "AND" und dann nochmal Inkrement.

Nochmal: das if hat mit der Bufferincrementierung nichts zu tun!!
Das ist eine Überprüfung (soviel ich verstanden habe) ob der Buffer frei 
ist mit den beiden Variablen r_in, r_out!!!!!!!!!
Das oder ähnliches brauchst du auch noch in Variant 2!!!!!

Nur die 2 Zeilen inkrementieren den Buffer:

 rbuf [r_in & (RBUF_SIZE-1)] = SBUF;
 r_in++;

und die sind definitiv schneller als als Variante 2

von (prx) A. K. (prx)


Lesenswert?

Zur Performance einzelner Assembler-Befehle:

- Bei einfachen Implementierungen mit sehr kurzer Pipeline, wie AVR, 
PIC8/16, 8051, kann man in sehr grober Näherung arithmetische Befehle 
mit bedingten Sprungbefehlen gleichsetzen. Das mögen dann 1 vs. 2-3 
Takte sein, aber dieser Unterschied ist nicht gross, verglichen mit...

- Bei High-End Implementierungen wie in aktuellen PC-Prozessoren sind 
bedingte Sprungbefehle im Regelfall ebenfalls billig, können aber in 
Einzelfällen auch über 100 Takte verbraten. Daher sind bei solchen 
Prozessoren bedingte Operationen/Zuweisungen immer wichtiger. Weshalb 
sowas wie
  i = (i + 1) % N;   // Bedingung komplett vermieden
  if (i < N) ++i;    // bedingte Zuweisung (x86) oder Operation (ARM)
sehr viel billiger sein kann, als ein komplexer if-Block mit 
Sprungbefehl
  if (i < 0) { ...; ...; ...; }

von Lens (Gast)


Lesenswert?

Hi,

Ja das stimmt. Ich hab nicht drann gedacht, dass der Mikrokontroller 
schnell genug ist, um die Daten im Empfangspuffer alle rechtzeitig 
fertig zu verarbeiten.

Danke für den Hinweis!

von Lens (Gast)


Lesenswert?

Noch eine Frage: Der Mikrokontroller gibt einiges der empfangenen 
Zeichen aus, einiges geht aber verloren, wird nicht ausgegeben, weil der 
Mikrokontroller bei manchen neu eingegeben Zeichen noch einen vollen 
Puffer hat (obwohl ich Variante-1 verwende). Verwendet wird eine 
Baudrate von 1200. Wie kann man dafür sorgen, dass alle Zeichen 
empfangen werden? Höhere Baudrate?

von (prx) A. K. (prx)


Lesenswert?

Wenn der Controller die Zeichen langsamer verarbeitet, als er sie 
empfangen kann, dann hilft eines von:
- Übertragungsrate/Baudrate entsprechend reduzieren(!),
- Verarbeitung der Zeichen beschleunigen,
- Dem Sender per Handshake mitteilen, dass grad nix mehr geht.

von Werner (Gast)


Lesenswert?

Lens schrieb:
> Wie kann man dafür sorgen, dass alle Zeichen empfangen werden?

Entweder indem man dafür garantiert, dass die Daten schnell genug 
verarbeitet werden oder indem man dem anderen Sender mitteilt, dass 
erstmal nix mehr geht (Hardware-Handshake, Software-Handshake oder 
Protokoll mit Empfangsbestätigung). Mit schnellerem Empfang kann noch 
mehr rein kommen, d.h. das bringt den Prozessor noch eher in Bedrängnis.

von Walter S. (avatar)


Lesenswert?

Lens schrieb:
> Ist doch das gleiche oder?

nein, wo bleibt denn da da rout,
das auslesen aus dem Buffer darfst du nicht vergessen

von Lens (Gast)


Lesenswert?

Ok. Super. Aber regeln muss man die Geschwindigkeit nicht nur Seitens 
Mikrokontroller, sondern auch Seitens der Terminalsoftware. Auch wenn 
ich die richtige Baudrate in der Terminalsoftware einstelle kommt der 
Mikrokontroller an vielen Stellen nicht mit.
Erst wenn ich in der Terminalsoftware eine zeitliche Verzögerung von 
"260ms" einstelle bekomm ich auch alle Ausgaben.
Der Mikrokontroller wird ganz schön langsam:)

von (prx) A. K. (prx)


Lesenswert?

Dass man die Baudrate auf beiden Seiten gleich einstellt hielt ich 
ursprünglich für selbstverständlich. ;-)

Ein Handshake-Verfahren hat gegenüber einer inhaltsunabhägig niedrigen 
Übertragungsrate dann einen Vorteil, wenn nur wenige Zeichen langsam 
verarbeitet werden, die meisten aber schnell.

von Lens (Gast)


Lesenswert?

Ah ja noch eine Frage hätte ich da:
Wieso setzt man in der Anwendung die Priorität vom "Serial Channel" auf 
0? Es gibt ja nichts anderes außer die serielle Schnittstelle, die in 
der Anwendung einen Interrupt auslösen kann

von Werner (Gast)


Lesenswert?

Lens schrieb:
> Erst wenn ich in der Terminalsoftware eine zeitliche Verzögerung von
> "260ms" einstelle bekomm ich auch alle Ausgaben.
> Der Mikrokontroller wird ganz schön langsam:)

Dann hast du in deiner Software ein Problem. Bei 1200Bd hat der µC sooh 
viel Zeit für die Verarbeitung der empfangenen Daten, genaugenommen 8 
Millisekunden pro Zeichen.

von (prx) A. K. (prx)


Lesenswert?

Lens schrieb:
> Wieso setzt man in der Anwendung die Priorität vom "Serial Channel"

Nicht jeder Code ist spezifisch für die Anwendung geschrieben. Ein 
Programmteil für die serielle Schnittstelle wird gerne in anderem Code 
weiterverwendet. So stammt dieser möglicherweise aus einer Anwendung, in 
der Prioritäten wichtig waren.

von Michael (Gast)


Lesenswert?

Lens schrieb:
> Wieso setzt man in der Anwendung die Priorität vom "Serial Channel" auf
> 0?

Vielleich erzählst du mal, von was für einer Anwendung du sprichst, um 
was für einen Prozessor es sich handelt und welches Betriebssystem 
darauf läuft?

von Lens (Gast)


Lesenswert?

Also es geht um ein "Keil-Projektbeispiel", bei dem ich an der ein oder 
anderen Stelle auch das Gefühl hab, dass manche Sachen aus einem anderen 
Projekt kopiert wurden. So wird z. B.
- 2x die "com_baudrate()"-Funktion aufgerufen.
- 2x TI auf 0 gesetzt in "com_baudrate()" und "com_initialize()"
--> Sind diese Redundanzen wirklich notwendig?

liebe Grüße

von Lens (Gast)


Lesenswert?


von Rechtschreiber (Gast)


Lesenswert?

fußnagel schrieb:
> So wird es noch geschmeidiger:
> http://www.duden.de/rechtschreibung/performant

Mal im ernst hier geht es Inhalte der Elektrotechnik nicht um 
Rechtschreibung. Diese ist für Behörden und Schule bindend, ansonsten 
kann jeder in Deutschland schreiben wie er will.

Bitte informiere dich mal über die deutsche Rechtschreibung, bevor du 
hier versuchst Menschen ohne einen Grund du diskreditieren.

von Lens (Gast)


Lesenswert?

An Rechtschreiber: Er kann doch selbst nicht richtig rechtschreiben. 
Fußnagel schreibt man groß :).. Ne aber jetzt zurück zum Thema..

von fußnagel (Gast)


Lesenswert?

Rechtschreiber schrieb:
> fußnagel schrieb:
>> So wird es noch geschmeidiger:
>> http://www.duden.de/rechtschreibung/performant
>
> Mal im ernst hier geht es Inhalte der Elektrotechnik nicht um
> Rechtschreibung. Diese ist für Behörden und Schule bindend, ansonsten
> kann jeder in Deutschland schreiben wie er will.
>
> Bitte informiere dich mal über die deutsche Rechtschreibung, bevor du
> hier versuchst Menschen ohne einen Grund du diskreditieren.

@Rechtschreiber: Ich sehe, daß du weniger zum Thema beizutragen hast als 
ich. Ich habe nicht diskreditiert, sondern versucht in der 
"geschliffenen" Ausdrucksweise noch Bugs beseitigen zu helfen :) Ich hab 
mich jetzt zwar auch nicht dran gehalten, aber: Do not feed the trolls 
:-)

von Lens (Gast)


Lesenswert?

Kann mir einer sagen wieso:
1. Die Redundanzen, die ich oben beschrieben habe gemacht wurden.
2. Wieso wird vor z. B. "void com_baudrate(unsigned baudrate)" das 
geschrieben: #pragma disabled
--> Ist doch garnicht notwendig, da EAL=1 sowieso erst nach Ausführung 
von
"com_baudrate()" gesetzt wird

von W.S. (Gast)


Lesenswert?

Lens schrieb:
> Folgender Code soll perfomant sein...

"This example works with any 8051-compatible device."

Du solltest dir nicht blindlings irgendwelche Codeschnipsel an Land 
ziehen, sondern dir selbst vorab Gedanken über die Struktur deines 
Programmes machen.

Zunächst sind irgendwelche #pragma xyz  meistens nicht portabel, du 
solltest sowas also im Zweifelsfall einfach weglassen.

Als nächstes sollte dir klar sein, daß das Programm in deinem uC 
normalerweise wesentlich schneller ist, als die Zeichen zum Rx-Eingang 
herein kommen - es sei denn, du hast einen saftigen Fehler in der 
Struktur gemacht. Über einen oder zwei Befehle beim Empfangs-Ringpuffer 
sooltest du dich daher nicht aufregen.

Ganz anders sieht es beim Senden aus: Da ist wiederum das Programm viel 
schneller, als die Zeichen zum Tx hinausgehen. Also solltest du dir 
einen deutlich größeren Sendepuffer gönnen, als der Empfangspuffer groß 
ist und das Senden natürlich per Interrupt erledigen.

Die einzige Ausnahme von dem Gesagten sehe ich dann, wenn der 
betreffende uC aus Stromspargründen nur mit 32 kHz läuft.

Ich komme mir zwar vor wie ne tibetanische Gebetsmühle, aber guck dir in 
der Codesammlung mal die "Lernbetty" an. Die dortigen I/O-Routinen für 
den seriellen Port funktionieren, sind m.E. auch gut verständlich 
geschrieben und lassen sich gut auf andere Systeme portieren. (Ähnliches 
gilt auch für die dortigen Kommando-Routinen und Konvertierungen)

W.S.

von (prx) A. K. (prx)


Lesenswert?

Wenn du ein HD44780-LCD als Ausgabedevice an die serielle Schnittstelle 
eines PCs hängst, dann kanns auch ohne Programmierfehler und bei 100MHz 
Takt passieren, dass die Schnittstelle den Code für ClearScreen 
schneller überträgt, als das Display ihn ausführt.

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.