memcpy ist ganz schön schnell...

Herakles

Profifragensteller
Moin!

Ich habe soeben etwas herausgefunden, was mich doch sehr verwundert hat. Ich stelle hier also jetzt ausnahmsweise mal keine Frage, sondern stelle einfach mal kurz ein Ergebnis vor.

Man denke sich ein Producer-Consumer Umfeld. Es kommen immer gleichgroße Pakete herein, die - einmal die volle Größe erreicht - anschließend zu verarbeiten sind. Die Pakete sind 512 Bytes groß.

Es bietet sich für dieses spezielle Problem kein Ringpuffer an, weil für den Fall, dass keine neuen Pakete eintrudeln, die alten Daten immer und immer wieder verwendet werden sollen. Also ist es einfacher, sich ein Kopierdatenfeld aufzumachen, in dem immer die zu verwendenden Daten stehen, als aufzupassen, ob neue Daten im Ringpuffer sind - obwohl, so blöd ist die Idee gar nicht fällt mir gerade auf. Naja, darum soll es hier nicht gehen :)

Ich habe mich gefragt, ob es wohl schneller geht, ein memcpy zu machen, in dem ich die 512 Byte von einem Speicher in einen anderen kopiere, oder ob ich einen Pointer verschiebe(Zugriff auf die alten Daten) und ein malloc mache(für die neu eintreffenden Daten). Das Interessante ist, dass das memcpy schneller geht.

Getestet habe ich das auf einem Atmel AVR32UC3A0512. Ich messe mit einem Oszilloskop immer die Dauer zwischen "port_low()" und "port_high()"(damit schalte ich einfach nur einen Pin, um eine Zeit messen zu können).

Hier mal ein wenig Pseudo-Code:

Mit memcpy:
Code:
void *P, *Q;
Q=malloc(512);
P=malloc(512);
port_low();
memcpy(P,Q,512);
port_high();

Mit malloc und pointerverschieben:
Code:
void *P, *Q, *T;
Q=malloc(512);
port_low();
P=malloc(512);
T=Q;
Q=P;
free(T);
port_high();

Das Ergebnis: Mit memcpy dauert der Vorgang 10us, mit malloc und pointerverschieben 16us.

Entweder das liegt daran, dass entweder malloc oder free viel Zeit benötigen, oder die höhere Anzahl an Befehlen bewirkt in Assembler längeren Code und der Prozessor muss einfach mehr machen.

Wundern tut es mich dennoch, denn es geht hier immerhin um das Kopieren von 512 Bytes. Erwartet hätte ich es genau andersherum.

Wie gesagt, keine Fragestellung hier, sondern einfach nur ein Aufschreiben für die Nachwelt(und sicher auch für mich selbst zum Nachschlagen in 10 Jahren :) )

Viele Grüße
Herakles
 
Malloc braucht viel Zeit und free noch viel mehr. Software die häufig Speicher reserviert oder freigibt, sollte immer gleich größere Brocken reservieren und das intern handhaben.

Aber so wie sich das für mich liest ist ein Ringpuffer hervorragend geeignet, keine Ahnung warum du da etwas rumkopierst oder ständig neuen Speicher anforderst. Einen Puffer legt man genau ein mal an und benutzt ihn dann.
 
Hey Kamikaze,

ach ja, ich hab den Versuch von oben auch schon verworfen, weil ich beim Beschreiben bemerkt habe, wie es eigentlich gemacht werden sollte. Ich arbeite in dem Programm nun mit einer Messagequeue und einem einzigen definierten Speicher als Ringpuffer.

Aber egal, davon ganz losgelöst, wie ich das nun gelöst habe oder lösen werde, wollte ich gern meine Messung präsentieren. Mir ging es nicht darum, zu hinterfrage, was ich wie mache, sondern eine Performancemessung aufzuzeigen, die ich vom Ergebnis her anders erwartet hätte(wegen der "vielen" Daten für das memcpy).

Herakles
 
Für micht ist dein Performanzvergleich auch nicht verwunderlich, da im Gegensatz
zu stupidem Kopieren von Daten bei Malloc und Free einiges unter der Haube
abgeht.

Aber jetzt nochmal zu deinem Code: Kannst du dir die ganze MemCpy-rerei
nicht sparen und einfach nur Zeiger tauschen bzw Einketten von unbenutzt nach
benutzt und umgekehrt?
 
Hi Döna,

klaro, mein Konzept ist inzwischen vollkommen anders. Was interessiert mich, was ich gestern gesagt habe? :huth:

Nein, im Ernst: Schon beim Schreiben dieses Eintrags ist mir aufgefallen, dass die Art und Weise totaler Unfug ist. Wie aber schon zuvor beschrieben, ging es mir nicht darum, meinen Code zu hinterfragen, sondern darum, die Performanz von zwei Methoden im Vergleich zu sehen.

Dennoch Danke für die Gedanken zum Thema!

Grüße
Herakles
 
Zurück
Oben