Hier ist der Auszug aus dem betreffenden Programm. Die Matrix img[][]
hat die Größe GRÖSSE × GRÖSSE und wird initialisiert bei:
img[j][i] = 2 * j + i
Dann res[][]
erstellen Sie eine Matrix , und jedes Feld hier ist der Durchschnitt der 9 Felder in der img-Matrix. Der Rand wird der Einfachheit halber bei 0 belassen.
for(i=1;i<SIZE-1;i++)
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
for(k=-1;k<2;k++)
for(l=-1;l<2;l++)
res[j][i] += img[j+l][i+k];
res[j][i] /= 9;
}
Das ist alles, was das Programm zu bieten hat. Der Vollständigkeit halber ist hier das, was vorher kommt. Es kommt kein Code mehr. Wie Sie sehen können, handelt es sich nur um eine Initialisierung.
#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
img[j][i] = (2*j+i)%8196;
Grundsätzlich ist dieses Programm langsam, wenn SIZE ein Vielfaches von 2048 ist, z. B. die Ausführungszeiten:
SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs
Der Compiler ist GCC. Soweit ich weiß, liegt dies an der Speicherverwaltung, aber ich weiß nicht wirklich viel über dieses Thema, weshalb ich hier frage.
Auch wie man das behebt, wäre schön, aber wenn jemand diese Ausführungszeiten erklären könnte, wäre ich schon glücklich genug.
Ich kenne malloc / free bereits, aber das Problem ist nicht die Menge des verwendeten Speichers, sondern lediglich die Ausführungszeit. Ich weiß also nicht, wie das helfen würde.
quelle
Antworten:
Der Unterschied wird durch dasselbe Super-Alignment-Problem bei den folgenden verwandten Fragen verursacht:
Das liegt aber nur daran, dass es ein weiteres Problem mit dem Code gibt.
Ausgehend von der ursprünglichen Schleife:
Beachten Sie zunächst, dass die beiden inneren Schleifen trivial sind. Sie können wie folgt abgewickelt werden:
Damit bleiben die beiden äußeren Schleifen, an denen wir interessiert sind.
Jetzt können wir sehen, dass das Problem in dieser Frage dasselbe ist: Warum wirkt sich die Reihenfolge der Schleifen auf die Leistung aus, wenn über ein 2D-Array iteriert wird?
Sie iterieren die Matrix spaltenweise statt zeilenweise.
Um dieses Problem zu lösen, sollten Sie die beiden Schleifen austauschen.
Dadurch entfällt der gesamte nicht sequentielle Zugriff vollständig, sodass Sie bei großen Zweierpotenzen keine zufälligen Verlangsamungen mehr erhalten.
Core i7 920 bei 3,5 GHz
Originalcode:
Vertauschte Außenschleifen:
quelle
Die folgenden Tests wurden mit dem Visual C ++ - Compiler durchgeführt, da dieser von der Standardinstallation von Qt Creator verwendet wird (ich denke, ohne Optimierungsflag). Bei der Verwendung von GCC gibt es keinen großen Unterschied zwischen der Version von Mystical und meinem "optimierten" Code. Die Schlussfolgerung ist also, dass Compiler-Optimierungen die Mikrooptimierung besser berücksichtigen als Menschen (ich endlich). Ich lasse den Rest meiner Antwort als Referenz.
Es ist nicht effizient, Bilder auf diese Weise zu verarbeiten. Es ist besser, eindimensionale Arrays zu verwenden. Die Verarbeitung aller Pixel erfolgt in einer Schleife. Der zufällige Zugriff auf Punkte kann erfolgen über:
In diesem speziellen Fall ist es besser, die Summe von drei Pixelgruppen horizontal zu berechnen und zwischenzuspeichern, da sie jeweils dreimal verwendet werden.
Ich habe einige Tests durchgeführt und ich denke, es lohnt sich zu teilen. Jedes Ergebnis besteht aus durchschnittlich fünf Tests.
Originalcode von user1615209:
Mystical's Version:
Zwei Durchgänge mit einem 1D-Array: erster Durchgang für horizontale Summen, zweiter Durchgang für vertikale Summe und Durchschnitt. Adressierung mit zwei Durchgängen mit drei Zeigern und nur solchen Inkrementen:
Zwei Durchgänge mit einem 1D-Array und Adressierung wie folgt:
Ein Durchgang zwischenspeichert horizontale Summen nur eine Zeile voraus, damit sie im Cache bleiben:
Fazit:
Ich bin sicher, es ist möglich, es viel besser zu machen.
HINWEIS Bitte beachten Sie, dass ich diese Antwort eher auf allgemeine Leistungsprobleme als auf das in Mysticals hervorragender Antwort erläuterte Cache-Problem geschrieben habe. Am Anfang war es nur Pseudocode. Ich wurde gebeten, Tests in den Kommentaren durchzuführen ... Hier ist eine komplett überarbeitete Version mit Tests.
quelle