Posts Tagged ‘C++’

Shared memory Allocator mit der STL

Ich habe mich die letzten Tage mit der STL herungeärgert. Ich wollte einen Allocator schreiben, welcher mir die STL-Container in ein Shared Memory Segment legt. Ich habe es nicht wirklich hinbekommen. Inzwischen weiß ich, dass es die Leute von boost auch nicht hinbekommen haben. Aus diesem Grund werde ich nun boost benutzen und hoffen, dass die Performance nicht zu schlecht (unter Windows) ist. Das geheimnis ist, dass man die Container nach implementiert und die Implementierung kommt arbeitet korrekt in einem Shared Memory Segment.

Mehrkern oder nicht Mehrkern, dass ist die Frage

Ich habe inzwischen ein paar Experimente mit verschiedenen Mehrkernarchitekturen gemacht. Ich habe verschiende Algorithmen mit Cilk++ implementiert. Dabei kam es zu interessanten Ergebnissen. Ich hatte von superlinearen Speedup bis zu einem Speedup unter 1 alles. Aber woran liegt das, dass die Ergebnisse so weit auseinander gehen? Die schlechten Ergebnisse habe ich auf einem 2 Sockel Intel Xeon E5420-System mit 32 GB RAM gemacht. In der Mitte lag ein 2 Sockel System mit Intel Xeon X5570 und 48 GB RAM Die besten Ergebnisse lieferte ein 4 Sockel Rechner mit 16 GB RAM und AMD Opteron 852 Prozessoren.

Eine Erklärung für das unterschiedliche abschneiden der Systeme ist die Anbindung an den RAM und die Caches. Bei dem AMD-System hat jeder (Einkern-) Prozessor privaten Cache und einen eignen Speicherkontroller. Hier gibt es keine Engpässe. Bei dem Intel Xeon X5570 sind die Speicherkontroller in der CPU, aber der L2 Cache ist shared zwischen 2 Kernen. Hyperthreading hat keine Verbesserung der Laufzeit gebacht. Am schlechtesten schnitt das Intel Xeon E5420-System ab. Die beiden Prozessoren gehen über die Nordbrücke, um an den RAM zu gelangen. Ab einer bestimmten Problemgröße wurden die Algorithmen über die Speicherzugriffe sequenzialisiert.

Dein Freund der Cachemiss

Ich habe in meinen letzten Eintrag über Superlinearen Speedup geschrieben. Caching Effekte lassen sich auch in sequenziellen Programmen ausnutzen. So kann man lässt sich die klassische Matrixmultiplikation um Größenordnungen beschleunigen.

Dazu muss man nur die Matrix B transponiert abspeichern. Wenn man jetzt duch die Spalten der Matrix B geht hat man eine höhere Lokalität und damit weniger Cachemisses.

#include <iostream>
#include <stdlib.h>
#include <time.h>
 
using namespace std;
 
void mul(double *A, double *B, double *C, int dim)
{
    int i, j, k;
    double s;
 
    for (i = 0; i < dim; i++){
        for (j = 0; j < dim; j++) {
            s = 0.0;
            for (k = 0; k < dim; ++k)
                s += A[dim*i +k] * B[dim*k+j];
 
            C[dim*i+j] = s;
        }
    }
}
 
void transpose(double *A, int dim){
 
        int i,j;
        double tmp;
 
    for (i = 0; i < dim; i++){
        for (j = i; j < dim; j++){
            tmp = A[dim*i+j];
            A[dim*i+j] =A[dim*j+i];
            A[dim*j+i] = tmp;
        }
    }
 
}
 
void mulfast(double *A, double *B, double *C, int dim)
{
    int i, j, k;
    double s;
 
    transpose(B, dim);
 
    for (i = 0; i < dim; ++i){
        for (j = 0; j < dim; ++j) {
            s = 0.0;
            for (k = 0; k < dim; ++k)
                // B is transposed !!
                s += A[dim*i +k] * B[dim*j+k];
 
            C[dim*i+j] = s;
        }
    }
 
    transpose(B, dim);
}
 
int main(){
 
    int dim = 1024;
    clock_t start, end;
 
    double* A = (double*) calloc(dim* dim, sizeof(double));
    double* B = (double*) calloc(dim* dim, sizeof(double));
    double* C = (double*) calloc(dim* dim, sizeof(double));
 
    start = clock();
    mul(A,B,C, dim);
    end = clock();
    cout << "normal implementation: " << (end-start) / CLOCKS_PER_SEC << " seconds" << endl;
 
    start = clock();
    mulfast(A,B,C, dim);
    end = clock();
    cout << "fast implementation: " << (end-start) / CLOCKS_PER_SEC << " seconds" << endl;
 
    return 0;
}

Superlinearer Speedup

Ich habe für meine Diplomarbeit die Matrixmultiplikation nach Strassen implementiert. Das ganze habe ich mit Cilk++ implementiert.superlinearer Speedup

Ich war recht erstaunt, als ich diese Ergebnisse gesehen habe. Es ist erklärbar, weswegen ich einen superlinearen Speedup erreicht habe. Wenn ich auf 4 CPUs rechne habe ich mehr Cache zur Verfügung. Diesen hohen Speedup kann man nur durch Caching Effekte erreichen.