Archive for the ‘HPC’ Category

Cloud Computing

Ich höre immer öfter von Cloud Computing. Jedes mal hört sich das ganze wie eine ganz neue Idee an. Dabei ist Cloud Computing, nach meiner Ansicht, ein alter Hut. Dieser hat bestimmt schon 50 Jahre auf dem Buckel. Was man unter Cloud Computing versteht kann nachlesen. Was ist aber der eigentliche Kern hinter der ganzen Geschichte?

Beim   Cloud Computing werden Rechen-, Speicherkapazitäten oder Dienste dynamisch zur Verfügung gestellt. Diese Kapazitäten und Dienste werden in der Regel über ein Netzwerk zugänglich gemacht. Auf den Mainframes der 1960er Jahre wurden auch Dienste und Ressourcen dynamisch angeboten und verwaltet. Die Rechenzeit wurde zum Teil auch bei den verschiedenen Kostenstellen gebucht. Auf diese Weise kann man auch aktuelle Enterprise-Server bzw. Mainframes ansetzten und dabei die Hardware dynamisch partitionieren.  Wo ist nun der Unterschied, ob man 4 volle Racks hat oder nur einen großen Rechner (1960 oder heute)?

Der Unterschied zu 1960 ist, das man seit einigen Jahren vorkonfiguriertes Blech mit entsprechenden Diensten kaufen kann. Ich habe den Vorteil, das ich auf das Blech und dem Dienst Garantie bekommen kann. Weiterhin gibt es Dienstleister, welche einen Dienste anbieten. Als Kunde muss man sich nicht mehr mit der Hardware belasten. Es ist aber durchaus interessant  im eigenen Rechenzentrum eine private Cloud zu betreiben. So kann man schnell auf sich änderte Bedingungen  reagieren.

Wenn ich es genau nehme, dann betreibe zu Hause meine eigene Cloud. Das Herzstück ist walhalla, auf ihn läuft ein Solaris 11 Express Edition. In dem Rechner sind einige Festplatten. Wenn ich etwas ausprobiere, dann erstelle ich schnell eine  Zone oder setzte mit VirtualBox ein Linux auf. Je nach dem was ich mache, erzeuge ich mir eine maßgeschneiderte Umgebung. Einige werden sich fragen, wozu der ganze Aufwand. Die Antwort ist ganz einfach: Es ist möglich und es macht mir Spaß. Den größten Mehrgewinn sehe ich darin, das ich mein System sauber halte. Denn ich weiß für was welche Zone gut ist.

P.S.: Ich habe 1960 gewählt, weil mir nichts besseres eingefallen ist.

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.