C: Speichergeschwindigkeit auf dynamisch zugewiesenen Arrays
Ich benötige Hilfe bei der Ausführung des folgenden Codes. Es führt ein Memcpy auf zwei dynamisch zugewiesenen Arrays beliebiger Größe durch:
int main()
{
double *a, *b;
unsigned n = 10000000, i;
a = malloc(n*sizeof(double));
b = malloc(n*sizeof(double));
for(i=0; i<n; i++) {
a[i] = 1.0;
/* b[i] = 0.0; */
}
tic();
bzero(b, n*sizeof(double));
toc("bzero1");
tic();
bzero(b, n*sizeof(double));
toc("bzero2");
tic();
memcpy(b, a, n*sizeof(double));
toc("memcpy");
}
Tic / Toc messen die Ausführungszeit.
Auf meinem Computer benötigt memcpy 0.035s (Linux, gcc Version 4.4.6). Wenn ich jetzt die Zeile auskommentiere, die das Ziel-Array b initialisiert, ist der Code dreimal schneller (!) - 0,011 Sekunden.
Ich habe ein ähnliches Verhalten beobachtet, wenn ich eine Schleife anstelle von memcpy verwende. Normalerweise interessiert mich das nicht, da es ausreicht, den Speicher zu 'initialisieren', bevor er verwendet wird. Jetzt muss ich jedoch eine einfache Speicherkopie durchführen und dies so schnell wie möglich. Das Initialisieren der Daten erfordert das Schreiben, z. 0 in den Speicher, was nicht notwendig ist und Zeit braucht. Und ich möchte eine Speicherkopie mit der gesamten verfügbaren Speicherbandbreite durchführen.
Gibt es eine Lösung für dieses Problem? Oder hängt es mit der Art und Weise zusammen, wie Linux mit dynamischem Speicher umgeht (eine Art langsame Seitenzuweisung?) Und kann nicht umgangen werden? Wie ist es auf anderen Systemen?
Bearbeiten: Die gleichen Ergebnisse werden mit gcc 4.6 erhalten. Ich habe -O3 zum Kompilieren verwendet.
Bearbeiten: Vielen Dank für Ihre Kommentare. Ich verstehe, dass Speicherzuordnung Zeit braucht. Ich glaube, es fällt mir schwer zu akzeptieren, dass es so lange dauert, viel länger als der eigentliche Speicherzugriff. Der Code wurde so geändert, dass er einen Benchmark für die Initialisierung von Array b mit zwei aufeinander folgenden bzero-Aufrufen enthält. Die Timings zeigen jetzt
bzero1 0.273981
bzero2 0.056803
memcpy 0.117934
Es ist klar, dass der erste bzero-Aufruf dies tutviel mehr als nur Nullen in den Speicher streamen - das ist Speicherzuordnung und Speichernullung. Der zweite bzero-Aufruf hingegen benötigt die Hälfte der Zeit, die für ein Memcpy erforderlich ist, was genau wie erwartet ist - schreibe nur Zeit vs. Lese- und Schreibzeit. Ich verstehe, dass der Overhead des zweiten bzero-Aufrufs aus Gründen der Betriebssystemsicherheit vorhanden sein muss. Was ist mit dem Rest? Kann ich es nicht irgendwie verringern, z. Verwenden Sie größere Speicherseiten? Unterschiedliche Kerneleinstellungen?
Ich sollte erwähnen, dass ich dies auf Ubuntu Wheeze laufen lasse.