6 Stimmen

Strukturen in C, sind sie effizient?

Ich lese gerade einen solchen C-Code:

double function( int lena,double xa,double ya, double za, double *acoefs, ...,
                 int lenb,double xb,double yb, double zb, double *bcoefs, ...,
                 same for c,
                 same for d )

Diese Funktion wird im Code mehr als 100.000 Mal aufgerufen, sie ist also leistungsentscheidend.

Ich versuche, diesen Code zu erweitern, aber ich möchte wissen, ob es effizient ist oder nicht (und wie viel dies die Geschwindigkeit beeinflusst), um alle Parameter in einer Struktur wie diese zu kapseln

struct PGTO { int len; double x,y,z ; double *acoefs }

und greifen dann auf die Parameter in der Funktion zu.

11 Stimmen

Einfacher Weg, das herauszufinden: Profil und Test

1 Stimmen

Der kompilierte Code sollte für die x86- und ARM-Standardaufrufkonvention gleich sein.

0 Stimmen

Ist die ... die varargs angeben, oder haben Sie einige Parameter weggelassen?

5voto

Nikolai Ruhe Punkte 80427

Die Antwort auf diese Frage hängt sehr stark von der Plattform und ihren Aufrufkonventionen ab. Sie hängt auch davon ab, ob die Funktion inlined werden kann und ob andere Compiler-Optimierungen möglich sind.

Ich würde sagen, auf vielen Plattformen könnte die struct-Version effizienter sein, da weniger Parameter auf den Stack kopiert werden müssen, wenn Sie einen Zeiger auf die struct übergeben.

Wie auch immer, die Frage ist nicht einfach zu beantworten. Also, wie bei allen Leistungsüberlegungen: Einfach testen und profilieren!

5voto

Roman Dmitrienko Punkte 2855

Zunächst einmal scheint die Verwendung von Strukturen in genau diesem Fall der richtige Weg zu sein. Der Code wird viel einfacher zu lesen und zu verstehen sein, es wird auch weniger unübersichtlich werden.

Die Übergabe eines Zeigers auf eine Struktur ist im Allgemeinen billiger als die Übergabe vieler Parameter.

5voto

jcoder Punkte 28716

Visual C++ 2008 64 Bit scheint die Struktur zu übergeben, indem der Aufrufer Platz für eine Kopie der Struktur auf seinem Stapel zuweisen und die Datenelemente in es kopieren und dann nur die Adresse dieser Kopie in die Funktion durch Wert übergeben.

Dieses einfache Beispiel wurde wie folgt zusammengestellt

struct data {
   int a;
   int b;
   int c;
   char d;
   float f;
};

double f2(data d)
{
    return d.a+d.b+d.c+d.d+d.f;
}

Kompiliert zu diesem -

movsx   eax, BYTE PTR [rcx+12]
add eax, DWORD PTR [rcx+8]
add eax, DWORD PTR [rcx+4]
add eax, DWORD PTR [rcx]
movd    xmm0, eax
cvtdq2ps xmm0, xmm0
addss   xmm0, DWORD PTR [rcx+16]
unpcklps xmm0, xmm0
cvtps2pd xmm0, xmm0
ret 0

Wenn Sie also einzelne Elemente übergeben, schiebt der Aufrufer sie auf den Stapel und die Funktion greift relativ zum Stapel auf sie zu. Bei der Übergabe einer Zeichenkette kopiert der Aufrufer die Datenelemente in einen Speicherblock auf dem Stack und übergibt dann die Adresse dieses Blocks an die Funktion, die dann relativ dazu auf die Daten zugreift.

Der zweite Weg hat ein paar mehr Assembler-Anweisungen, aber das ist es, so weit ich aus meinen Tests sagen kann, gibt es keinen signifikanten Unterschied in der Effizienz zwischen den beiden Methoden überhaupt andere als ein paar Mikrosekunden. In allen meinen Tests wollte der Compiler sowieso alle Aufrufe inline schalten, es sei denn, ich zwang ihn, sie über einen Zeiger aufzurufen, so dass es möglich ist, dass in Ihrem echten Programm überhaupt nichts über den Stack übergeben wird.

Meiner Meinung nach ist die Verwendung einer Struktur übersichtlicher und es scheint keine signifikanten Geschwindigkeitsunterschiede zu geben, also entscheide dich für diese :)

Wie immer, wenn Sie Zweifel an der Leistung haben, müssen Sie ein Profil Ihrer genauen Konfiguration erstellen.

1voto

Mike Dunlavey Punkte 39339

Ich nehme an, es hängt davon ab, wie oft Sie die Struktur auffüllen müssen.

Die Übergabe eines einzelnen Zeigers auf eine Struktur (4 Bytes) erfordert weniger Anweisungen als die Übergabe eines int, 3 Doubles und eines Zeigers (32 Bytes), aber wenn Sie die Struktur mit diesen 32 Bytes füllen müssen, bevor Sie den Aufruf durchführen, dann haben Sie den Vorteil verloren.

Auf jeden Fall ist die Leistung immer relativ, so dass der einzige Weg, um festzustellen, ob es sich lohnt, ist zu sehen, wie viel Prozent der Zeit in der Übergabe dieser Argumente ausgegeben wird. Dazu lasse ich das Programm einfach laufen und pausiere es 10 oder 20 Mal nach dem Zufallsprinzip. Wenn ich nicht mehr als 10 % der Zeit mit der Übergabe dieser Argumente verbringe, gibt es wahrscheinlich größere Probleme, die zuerst behoben werden könnten.

0voto

Sad Developer Punkte 1198

Moderne Compiler werden höchstwahrscheinlich in beiden Fällen identischen Code erzeugen. Sofern Ihr Compiler nicht auf dem neuesten Stand der Technik ist, ist der einzige (aber wichtige) Vorteil, den Sie mit Strukturen erzielen, die bessere Lesbarkeit.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X