C Singelthread schneller als Pthread?

@leboh
Ist klar, das überlässt man bei richtigen Anwendungen den Fachleuten oder beschäftigt sich eingehend damit... um es dann doch wieder den Fachleuten zu überlassen. Hab mal in ein Buch über Monte-Carlo-Simulationen geschaut und da war auch ¾ vom Inhalt über Zufallszahlen, hat mich dann ziemlich abgeschreckt, aber momentan mache ich vieles schlicht, damit ich was zum Programmieren habe und mich mit verschiedenen Probleme rumschlagen kann und dann hoffentlich was lerne.

@kuddlmuddl
Mit dem Risiko, dass das eine blöde Frage ist: Was meinst du mit Partikelfiltern in diesem Kontext?

Ich hab jetzt mal .txt-Dateien mit Zufallszahlen gefüllt und lasse diese vom singlethread-Programm auslesen um mit ihnen zu arbeiten. Zum Vergleich habe ich noch eine Version vom singelthread-Programm, dass genau gleich aussieht, aber die Zahlen selbst erzeugt. Das Programm, das selbst erzeugt ist etwa 10 mal schneller, d.h. fúr mich lohnt es sich kaum, die Zahlen vorzubereiten. Evtl. mache ich beim Auslesen was nicht optimal?
Code:
File *random_numbers;
random_numbers = fopen("random_numbers.txt","r");
[...]
fscanf(random_numbers, "%f", &randno)
[...]
Ich schau mir jetzt mal den Mersenne twister an, bzw zuerst bit-Operationen (habe ich bis jetzt noch nie benötigt), der ist laut Wikipedia der Standard-Generator für Monte-Carlo-Anwendungen, daher sicher auch ein wenig genauerer Betrachtung würdig.

Zum Thema Tabellisierung:
Dann müsste ich ja für einen gegebenen Wertebereich [a,b] je nach a und b wieder neue Tabellen berechnen. Dann noch in ein Programm einlesen und gezielt auslesen. Das ist ja auch ein grosser Rechenaufwand, gibt es da Faustregeln, wann der Vorteil der Tabelle den Nachteil des Auslesens überwiegt? bspw. dass ein scanf etwa 130 floating-point-operations entspricht, während ein sin(x) etwa 50 entspricht oder so? (ok, sin wird wohl über taylor-approximation berechnet, wo man etwa die flop schätzen könnte).

Gruss,
mahatma
Ergänzung ()

So, habe jetzt diese (Link) Vorlage für den Mersenne Twister benutzt und bin (im singlethread) Programm etwa 1% langsamer, eher weniger. jedoch ist mein Resultat nun viel schlechter!
Im Test soll das Integral von x² berechnet werden im Interval [0,10]. Das Ergebnis sollte 333.333... sein, jedoch gibt das Programm mit dem Mersenne Twister Algo konsistent nur 33X.XXX aus, wobei die X nicht Dreien sind ( ;) ), die Version mit dem normalen rand() jedoch 333.3XX.

Was zum Teufel?

Ein Ort, wo ich den Fehler vermuten würde, ist die Umwandlung von unsigned int zu einem float, der bei mir so passiert (kopiert ist die ganze Funktion, die fettmarkierte Zeile enthält die
Umwandlung über einen Cast zu (float) für den Bruch über einen (long), wobei eine Änderung von long zu unsigned long keine Verbesserung bringt.

Code:
void kernel( double a, double b, double (*function)(double), double* integral_val){
                // a and b are the boundaries of the interval, *function a pointer to the function to be integrated and the result will be saved at integral_val
		double value_sum=0;
		int i;
		int rand_counter = 0;
		long  mt_MAX = pow(2,32)-1;//maximum value of mt_random[]
		float rand_zero_one;//random number between zero and one
		float rand_interval;//random number in interval given by a and b

		for(i=0; i<N; i++){
				
				//if mt_buffer has been read, start over at the beginning and create new random numbers
				if(rand_counter==MT_LEN){
						mt_random();
						rand_counter=0;
				}
				
[B]				rand_zero_one = (float)mt_buffer[rand_counter]/mt_MAX;[/B]
				rand_interval = rand_zero_one*(b-a)+a;
				
				value_sum += function( rand_interval );
				
				rand_counter++;
		}

		//save result in integral_val
		*integral_val = (double)(b-a)*1.f/N*value_sum;
}
 
Auf die schnelle keine Idee, ausser: Warum machst Du float und nicht durchgehend double?
 
Mist, das ist ein überbleibsel aus der (falschen) Annahme, dass CUDA keine double-precision kann, was jedoch mittlerweilen möglich ist. Werde das noch ändern, denke jedoch nicht, dass das gross hilft.

Wenn ich mich recht erinnere, kann es bei unsigned-variabeln zu Problemen kommen bei bestimmten Operationen, könnte das sein, dass das bei der Division auch der Fall ist? Sonst schreib ich später noch ein Programm, dass nur diese Mersenne-Twister-Zahlen ausgibt normalisiert auf [0,1] und plotte das mal, um zu schauen, ob es eine gute Verteilung gibt.
 
Also was dein Code da macht, ist mir wirklich nicht klar. Du willst irgendwie aus dem Mersenne Twister State (mt_buffer) deine Zufallszahl generieren. Aber diese wir doch bereits von mt_random() zurückgeliefert. Der Buffer und andere Details der Implementierung haben dich nicht zu interessieren.



Hast du den Code nochmal angepasst? Denn der Code da ist nicht threadsicher! Jeder Thread würde auf den globalen mt_buffer zugreifen.

Du solltest den Code am besten nach folgendem Muster umbauen:
PHP:
unsigned long mt_random(unsigned long &mt_buffer[MT_LEN]);
Jeder Thread gibt bei jeder Operation einen mt_buffer in die Funktion rein. Der Mersenne Twister arbeitet damit, modifiziert diesen und erzeugt die Zufallszahl.

Das Ziel ist, dass die Funktion mt_random() nur von Parametern und keinem globalen State abhängt, dann ist die garantiert threadsicher, da sie threadlocal ist. Und du brauchst keine Synchronisierung.
 
Ok, so geht's natürlich auch und wahrscheinlich auch besser, wie du es beschrieben hast.

Meine Version ist noch nicht threadsicher, das stimmt, jedoch hätte ich für Threadsicherheit schlicht den mt_buffer 2 Dimensional gemacht, also mt_buffer[Länge][threadidx] und dann jedem Thread eine Spalte davon zugeordnet, die er auch individuell updaten kann. So wäre er auch threadsicher.

Und ob ich jetzt direkt auf den globalen Array zugreife oder mir einen Pointer auf das erste Element zurückgeben lasse und dann auf dieses Zugreife, das ja doch nur auf den gleichen Array zeigt, wird, denke ich, egal sein, abgesehen davon, dass es nicht so schön ist.

Daran soll also die Genauigkeit nicht scheitern, aber ich implementiers jetzt mal so, wie von dir empfohlen, damit ich es auf die mehr-thread-Anwendung einfacher übertragen kann, dankeschön.
Ergänzung ()

Noch eine Frage zum Mersenne-Twister:

In der Funktion, die ich verlinkt habe, wird von der Funktion mt_random ein Pointer zu einem Wert im Array zurückgegeben, d.h. dass ich bei jedem Aufruf der Funktion doch 624 Zufallszahlen berechne, aber nur eine auslese, oder?

Kann ich da nicht gleich alle Werte benutzen, die im Array sind ,also pointer zum ersten WErt zurückgeben lassen, array durchgehen und dann wieder die Funktion mt_random aufrufen, wenn ich am Ende vom Array bin und wieder beim ersten Beitrag beginnen?

Edit: Gerade gesehen, nur der letzte Wert wird zurückgegeben, dieser wandert dann durch den Array der jedoch jedesmal neu generiert wird?
 
Zuletzt bearbeitet:
Was meinst du mit Partikelfiltern in diesem Kontext?
Ist mehr oder weniger ein anderer Name für Monte-Carlo Verfahren.
SMC
Bei nem Partikelfilter würde jeder deiner gestreuten Punkte noch irgendwas kluges machen und jeder Thread würde einen Pool von Partikeln verwalten. Oder man startet je Partikel einen Thread.. je nach Algorithmus.
Die Monte-Carlo-Integration (aka "Mit geworfenen Reiskörnern die Fläche eines Kreises schätzen ohne die Zahl PI zu kennen, indem man einen Kreis malt und zählt wie viele drin landen") ist imho der einfachste Einstieg in diese Welt der Verfahren. Sie haben halt gemeinsam dass durch endlich viele Instanzen/Partikel/Hypothesen/Vermutungen/Modellen ein reelwertiger Raum approximert wird. Weiß nicht wie man es besser formulieren soll. Sehr erfolgreich (da viel schneller als alternative Verfahren) setzt man die für http://de.wikipedia.org/wiki/Tracking oder http://de.wikipedia.org/wiki/Simultaneous_Localization_and_Mapping ein.

Grundsätzlich hab ich das Gefühl du verrennst dich mit deiner Zeitmessung etwas. Insbesondere wegen diesen beiden Sachen:
Ich hab jetzt mal .txt-Dateien mit Zufallszahlen gefüllt und lasse diese vom singlethread-Programm auslesen um mit ihnen zu arbeiten. Zum Vergleich habe ich noch eine Version vom singelthread-Programm, dass genau gleich aussieht, aber die Zahlen selbst erzeugt. Das Programm, das selbst erzeugt ist etwa 10 mal schneller, d.h. fúr mich lohnt es sich kaum, die Zahlen vorzubereiten. Evtl. mache ich beim Auslesen was nicht optimal?
Dann müsste ich ja für einen gegebenen Wertebereich [a,b] je nach a und b wieder neue Tabellen berechnen. Dann noch in ein Programm einlesen und gezielt auslesen. Das ist ja auch ein grosser Rechenaufwand, gibt es da Faustregeln, wann der Vorteil der Tabelle den Nachteil des Auslesens überwiegt? bspw. dass ein scanf etwa 130 floating-point-operations entspricht, während ein sin(x) etwa 50 entspricht oder so? (ok, sin wird wohl über taylor-approximation berechnet, wo man etwa die flop schätzen könnte).

Dir geht es scheinbar darum die Zeit zwischen "Start des Programms" und "Ergebnis ist auf dem Bildschirm" zu minimieren.
Das ist äußert ungewöhnlich! Guck dir mal die Welt der Spiele, Robotik, sonstiger Real-Time Systeme oder HPC an die ständig nach mehr Leistung verlangen.
Es geht immer darum ZUR LAUFZEIT den Rechen und IO Aufwand so gering wie möglich zu haben um in den engen Zeitgrenzen (Framerate bei Spielen, Bildrate einer Roboter-Kamera mit anschließender Bildverarbeitung, Frequenz der Datenverarbeitung eines RT Systems wie ESP, ABS, ...) alle nörtigen Berechnungen abzuschließen. (Wird auch weiche Echtzeit genannt). Ob aber das System bei der Initialisierung - also in deinem Fall wenn du das Programm startest - einige Sekunden benötigt um zB häufig benötigte Zwischenergebnisse Vorzurechnen, eine LUT auszulesen oder einfach nur Daten von der Festplatte in den RAM zu laden ist idR vollkommen unerheblich.
Dh deine Zielsetzung und die der meisten Leute die Multithreading/Laufzeitoptimierungen machen ist grundverschieden wenn nicht sogar gegenteilig.
Bei einem Spiele-Entwickler würde man sich freuen wenn man die FPS um 25% erhöhn könnte indem das Spiel ein paar Sekunden länger läd. Bei dir ist das unerwünscht..
Wenn du also mit Multicore-Support anfängst und dir über Laufzeiten gedanken machst solltest du evtl den Programmstart ignorieren und die reine Laufzeit deines Algorithmus messen.
 
Zuletzt bearbeitet:
@kuddlmuddl

Effektiv habe ich mich da etwas verrannt, habe mir zumindest die Überlegungen über den Unterschied der Laufzeit und der Start-Programm-bis-ende-Zeit zumindest so nie überlegt; ich hasse das, wenn ich solche Dinge übersehe :rolleyes:

Ich muss mir da noch ein paar grundsätzliche Gedanken machen und dann evtl. noch etwas in die Literatur gehen bzw. mal ein Date machen mit dem Assistenten, der den C-Einführungskurs gegeben hat, der schreibt eben auch Software fürs Cern.

Wobei ich davon ausgehe, dass die Anforderungen an Software im Cern andere sind als in der Robotik, welche wiederum anders sind als bei Kosmologen.

Momentan geht's (mir) vor allem darum, mit Threads einigermassen intelligent zu arbeiten, s.d. die multithread Anwendung mindestens so schnell sind wie ein einzelner Thread, besser bis 4 mal schneller.

aus Interesse, darf ich fragen was du so (beruflich/ausbildungsmässig) so machst?

@ice-breaker
Ich muss noch den mt_index mitgeben, aber kann ich die von dir vorgeschlagene Lösung sehr einfach implementieren. Es läuft auch, Ergebnisse sind auch etwa so genau wie mit rand() (kann ich natürlich nicht richtig beurteilen ohne systematisch Analyse, aber so von der Anzahl richtiger Ziffern passt's) Momentan aber nur singlethreaded - pthread Implementierung folgt, Danke!
 
Hallo,

um mal zu zeigen wie es sowas mit Openmp aussieht, Berechnung von Pi
mit Montecarlo Methode.

Das kann mit uebersetzen mit
gcc oder mit gcc -fopenmp, und bekommt eine serielle oder eine parallele Version.

Was wird gemacht:
das #pragma omp parallel erzeugt threads, dahinter wird definiert ob die Variablen
shared oder private sind.
Das #pragma omp for fuehrt dann den Loop aus, jeder Thread einen Teil davon,
das reduction(+:in) sorgt dafuer dass am Ende in "in" die Summe der Teilergebnisse
der Threads stehen.

In meinen Augen ist das einfacher als pthreads...

Code:
#include <stdlib.h>
#include <stdio.h>

#define N 100000000

main()
{
        double x,y;
        struct drand48_data buffer;
        long i;
        double in=0;
        unsigned short int seed[3];

#pragma omp parallel default(none) private(seed,buffer,x,y,i) shared(in)
        {
                seed[0]=145;
                seed[1]=78;
                seed[2]=clock();
                seed48_r(seed,&buffer);

#pragma omp for reduction(+:in)
                for(i=0; i<N; i++) {
                        drand48_r(&buffer, &x);
                        drand48_r(&buffer, &y);
                        if((x*x + y*y) <= 1.0) {
                                in++;
                        }
                }
        }
        printf("pi=%lf\n",4.0*(in/N));
}
 
Momentan geht's (mir) vor allem darum, mit Threads einigermassen intelligent zu arbeiten, s.d. die multithread Anwendung mindestens so schnell sind wie ein einzelner Thread, besser bis 4 mal schneller.
Das ist sicher ein sinnvolles Ziel. Wenn mans einmal mit pthread gemacht hat ist es auch kein nennenswerter Aufwand eine Funktion einfach 4x aufzurufen.
Anstatt die Argumente der Funktion nach der "(" aufzulisten macht man halt das struct und an der Stelle wo die Funktion aufgerufen werden soll macht man halt die Threads.
Laufzeitmessen würde ich aber immer ohne den Festplatten iO da der auch von vielen anderen Faktoren abhängt wie zB ob der Virenscanner sich gerade aktualisiert, ob das WIndows gerade ein Update läd usw.

darf ich fragen was du so (beruflich/ausbildungsmässig) so machst?
klar. ich hab info mit schwerpunkt bildverarbeitung (und ein bisschen mathe) an der uni hamburg studiert. In meiner Diplomarbeit hab ich den einzigen real brauchbaren SLAM Algorithmus implementiert der erst 2003 "erfunden" wurde. Der Prof der dazu die Doktorarbeit betreut hat in der der Algo zum ersten mal real auf nem PC umgesetzt wurde ist aktuell evtl. der bekannteste Roboterprof der Welt: Sebastian Thrun. Der leitet immerhin die Projektgruppe bei Google zum Thema autonomes Fahren: klick1, klick2, klick3
Da der Algo im Kern auf einen Partikelfilter aufsetzt musste ich mich sehr intensiv damit beschäftigen.. Ich finds immernoch ein hochspannendes Thema.
Leider gibts in dem Bereich autonomer Fahrzeuge nur sehr wenige Jobs und da ich aus Hamburg nicht weg wollte bin ich nun doch im Bereich Bildverarbeitung als Softwareentwickler gelandet.
LIDAR Sensoren sind leider extrem teuer so dass ich da Hobbymäßig nicht weitermachen kann auch wenn ich sehr gerne würde :-/ Der Sensor den ich für meine DiplArbeit benutzen durfte kostet >10k€ und um das mit anderen Sensoren zu realisieren bzw die an nem Fahrzeug anzubringen fehlt mir das E-Technik Grundwissen :/ Hab von Hardwarelöten und Platinenkram quasi 0 Ahnung.
Naja und wie das so ist wenn man einmal nen 40h-Job hat.. man ist abends auch froh einfach mal Feierabend zu haben. Meine Freundin würde mir auch nen Vogel zeigen wenn ich dann noch Programmieren würde ;)
 
Zuletzt bearbeitet:
So, Projekt Monte_Carlo_Integral ist jetzt mehr oder weniger im trockenen :D

sowohl single-thread, pthread wie auch cuda-Implementierung funktionieren, liefern das richtige Resultat und bewegen sichin (intuitiv zumindest) realistischen Zeitspannen.

Integriert wird jetzt sin(x)*exp(-x) von 0 bis 100 mit einer Milliarde Versuchen. Die Zeitmessungen sind noch nicht 'intelligent', starten also irgendwo in der Definition der ersten Variabeln und endet nachdem das Resultat ausgegeben wurde, für einen einfachen Vergleich reichts mir aber für den Moment:

singlethread: 77.7 Sekunden (ohne pthread, einfachst mögliches programm)

pthread 1 thread: 79 Sekunden
pthread 4 threads: 21.6 Sekunden
pthread 6 threads: 22.0 Sekunden
pthread 200 threads: 19.87 Sekunden

cuda um die 2000 threads: 0.3 Sekunden

wichtig:
-pthread unterteilt den Integrationsinterval in kleine Teile, die jeweils von einem Thread bearbeitet werden, während bei cuda jeder Thread im gesament Interval [0,100] rumratet.
-cuda hat sich beklagt,es könne keine double-operationen, deshalb ist arbeitet die Cuda-Version nur mit floats anstatt doubles wie bei den anderen. (sollte aber gehen, gibt evtl. eine -flag dafür)

Nun macht es imho Sinn, dass pthread mit einem thread langsamer ist als die singlethread-Anwendung, da das pthread-Programm schlicht grösser ist, pthreads kreiert werden müssen, casts auf die Vektoren mit den Funktionsanweisungen usw. Die 2 Sekunden finde ich zwar etwas viel, aber würde ich jetzt nicht als krass beurteilen.

Was mich überrascht ist, dass 200 threads weniger Zeit brauchen als 22, obwohl mein i5 angeblich kein Hyperthreading unterstützt. Erwartet habe ich, dass es viel langsamer wäre, weil der pthread-Overhead zunimmt und bspw. mutexen das ganze ja verlangsamen sollten - hat da wer eine Idee, warum das so sein könnte, dass 200 threads trotzdem schneller sind?

Cuda Performance ist toll, aber ich machs morgen mal mit mehr threads und schau ob meine GraKa (gtx 570) doubles kann, damit Vergleichbarkeit gegeben ist, sonst werden single- und pthread-Anwendung halt auf float downgegraded.

@leboh
Sieht interessant aus, auch wenn ich nicht ganz durchblicke. Aber pthreads finde ich jetzt (auch wenn ich ganz offensichtlich Startschwierigkeiten habe) nicht extremes Teufelswerk. Trotzdem mache ich am Wochenende evtl. ein kleines openmp-tutorial und komm dann auf dein Beispiel zurück :)

@ kuddlmuddl
Sehr spannend, danke.

Und einen Dank an deine Freundin, dass sie dich am Abend noch ins Netz lässt, damit du unbedarften Neuprogrammierern helfen kannst:D:p
 
--gpu-name sm_13 sollte bei Cuda helfen.
Dass die vielen Threads schneller sind ist ein bischen verdaechtig, sowas kann eigentlich nur sein
wenn die z.B. I/O machen, und die CPU gar nicht die ganze Zeit nutzen.
 
Ja genau leboh, danke, wusste doch, dass die Flag etwas mit der compute capability zu tun hatte, daher auch -arch sm_20, aber ist schon nah drann.

So, nun mit doubles braucht die Cuda-Version ziemlich genau eine Sekunde. Das ginge wahrscheinlich noch schneller, aber aktuell benutze ich als Initialisierung für den Mersenne Twister-array einfach vielfache der einzigartigen threadid (unique = einzigartig? klingt komisch) = thread.idx+blockid.x * blocksPerGrid, damit die Zufallszahlen trotzdem ok sind, lässt jeder thread den Mersenne Twister zuerst 8000 durchlaufen, das garantiert auch bei schlechtester initialisierung (eine 1 im ersten array-Eintrag) angeblich gute Zufallszahlen. Mit besserer Initialisierung könnte ich das wahrscheinlich stark beschleunigen.

@leboh
Also die Kerne sind (laut Fedorah Resource-Monitor) alle voll ausgelastet, kann mir das auch nicht erklären. :freak:
I/O ist ja input/output, meinst du damit nur von der Festplatte laden oder wäre auch vom Cache auf der CPU verschieben I/O? Selbst dann wüsste ich nicht, wo gross kommuniziert werden muss, der vollständige Code wäre hier einsehbar (Link). Wenn der Code ein zu grosser Krampf ist, wäre ich trotzdem froh über generellen input.
 
Also ich sehe da auf Anhieb auch keinen Fehler, habe aber auch länger nimmer mit C gearbeitet. Irgendein Fehler muss aber vorhanden sein. Der Scheduling-Overhead für 200 Threads muss deutlich einer 5-7 Threads Variante auf einem Quadcore unterliegen.
 
mal ne doofe frage... was solld a rauskommen? war nicht 333 ungefaehr die Loesung?
Bei mir macht die multithreaded Version Mist, da kommt was falsches raus.

integral in thread is 0.126366
integral in thread is 0.192514
integral in thread is 0.130925
integral in thread is 0.058508
integral in thread is 0.000115
integral in thread is 0.000362
integral in thread is -0.002599
integral in thread is 0.000216
integral in thread is -0.005232
integral in thread is 0.000028
integral in thread is 0.000252
integral in thread is -0.000009
integral in thread is -0.005748
integral in thread is 0.013283
integral in thread is -0.008347
integral in thread is -0.000609
the result is 0.500026
time elapsed is 7.924771



Ich habe mal spasseshalber aus der seriellen Version die da auch liegt eine OpenMP Version gemacht.

seriell
the result is 333.339997
time elapsed is 15.251584

parallel
the result is 333.338501
time elapsed is 0.637696

Ich sehe auch noch einen leichten Gewinn durch Hyperthreading, der Speedup ist groesser
als die Zahl der Cores, aber es wird dann mit noch mehr Threads nicht noch schneller.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>

#define N 1000000000.f
#define MT_LEN 624

unsigned long  mt_MAX;
//where a is the lower, b the upper boundary of the integral over the fucntion that fvalue point to. result will be stored in integral_val
void kernel( double a, double b, double (*fvalue)(double), double* integral_val);

//returns value of f(x)
double fvalue(double x);

//returns timerefference
double second();

//initializes mt_buffer with random numbers
void mt_init(unsigned long *mt_buffer, int *mt_index);

//creates new random numbers in mt_buffer with the mersenne-twister method
unsigned long mt_random(unsigned long *mt_buffer, int *mt_index);



int main(){
                double a,b;//boundaries
                double result;
                double start, end;//for time measurement
                srand( time (NULL) );//seed for rand()
                mt_MAX = pow(2,32)-1;//maximum value of mt_random[]

                start = second();

                a = 0;
                b = 10;

                kernel( a, b, fvalue, &result);
                printf("the result is %f\n", result);

                end = second();
                printf("time elapsed is %f\n",(end-start));

                return 0;
}



void kernel( double a, double b, double (*function)(double), double* integral_val){
                double value_sum=0;
                long i;
                double rand_zero_one;//random number between zero and one
                double rand_interval;//random number in interval given by a and b
                unsigned long* mt_buffer;
                int mt_index;

#pragma omp parallel default(none) private(mt_index,mt_buffer,i,rand_zero_one,rand_interval) shared(value_sum) firstprivate(a,b,mt_MAX,function)
                {
                mt_buffer = (unsigned long*)malloc( MT_LEN * sizeof(unsigned long));

                mt_init(mt_buffer, &mt_index);

#pragma omp for reduction(+:value_sum)
                for( i=0; i<(long)N; i++) {

                                rand_zero_one = (double)mt_random(mt_buffer, &mt_index)/mt_MAX;
                                rand_interval = rand_zero_one*(b-a)+a;

                                value_sum += function( rand_interval );
                }


                }
                //save result in integral_val
                *integral_val = (double)(b-a)*1.f/N*value_sum;
}



double fvalue(double x){
                return x*x;
}



//returns reference time
double second(){
                struct timeval t;
                gettimeofday( &t, (struct timezone*)0);
                return (double)(t.tv_sec + (double)t.tv_usec/1000000.0);
}



//below is code for the mersenne twister, call mt_init first to initialize the twister, then call mt_random to fill the array mt_buffer with new random numbers
void mt_init(unsigned long* mt_buffer, int *mt_index) {
                int i;
                for (i = 0; i < MT_LEN; i++){
                                mt_buffer[i] = rand();
                }
                *mt_index = 0;
}

//definitions necessary for mt_random
#define MT_IA           397
#define MT_IB           (MT_LEN - MT_IA)
#define UPPER_MASK      0x80000000
#define LOWER_MASK      0x7FFFFFFF
#define MATRIX_A        0x9908B0DF
#define TWIST(b,i,j)    ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK)
#define MAGIC(s)        (((s)&1)*MATRIX_A)



unsigned long mt_random(unsigned long* mt_buffer, int *mt_index) {
                unsigned long * b = mt_buffer;
                int idx = *mt_index;
                unsigned long s;
                int i;

                if (idx == MT_LEN*sizeof(unsigned long))
                {
                                idx = 0;
                                i = 0;
                                for (; i < MT_IB; i++) {
                                                s = TWIST(b, i, i+1);
                                                b[i] = b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s);
                                }
                                for (; i < MT_LEN-1; i++) {
                                                s = TWIST(b, i, i+1);
                                                b[i] = b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s);
                                }

                                s = TWIST(b, MT_LEN-1, 0);
                                b[MT_LEN-1] = b[MT_IA-1] ^ (s >> 1) ^ MAGIC(s);
                }
                *mt_index = idx + sizeof(unsigned long);
                return *(unsigned long *)((unsigned char *)b + idx);
                /* Here there is a commented out block in MB's original program */
}
 
@leboh

sorry, habe die Funktion gewechselt, ohne etwas mitzuteilen (damit die Funktion nicht nur eine floating-point operation ist). Momentan ist die Funktion sin(x)*exp(-x) von 1 bis 100 integriert. X*X gibt natürlich 333, da hast du vollkommen recht und meine früheren Beispiele waren auch so.

Zu deinem Code;

WTF

Nur ein dreissigstel der Zeit? hast du 4 octacores? Schau mir gleich mal den Code an aber das ist ja extrem!
 
ah ok, stimmt, hatte mich noch gewundert dass da -lm gebraucht wird.

wenn ich das Ding in meiner Version einbaue habe ich

the result is 0.499993
time elapsed is 4.472041

die pthread liefert

integral in thread is 0.126365
integral in thread is 0.130923
integral in thread is 0.192515
integral in thread is 0.058508
integral in thread is 0.000115
integral in thread is 0.000362
integral in thread is -0.008347
integral in thread is -0.002599
integral in thread is 0.000216
integral in thread is -0.000609
integral in thread is 0.000028
integral in thread is 0.000252
integral in thread is 0.013284
integral in thread is -0.005748
integral in thread is -0.005231
integral in thread is -0.000009
the result is 0.500026
time elapsed is 5.640833

Rechner ist Dual-8-core, also 16 cores, 32 threads.
Ergänzung ()

ich habe ein paar double-float casts entfernt, das wird eher bremsen denke ich mal.
 
So, hab mal dieses openMP-Tutorial angeschaut und es sieht nicht schlecht aus. Es scheint auch deutlich einfacher zu sein, eine single-thread Anwendung multithread-fähig zu machen. Trotzdem fühle ich mich (spontan, völlig unbegründet und evtl. zu meinem Nachteil) zu pthreads mehr hingezogen, da man mehr Bezug hat zu den Threads.

Daher denke ich mal, werde ich vorläufig mal die pthread-Schiene weiterfahren (solange ich sowieso nur aus Freude am lernen bin) und wenn ich dann effektiv mal für eine Anwendung was schreiben muss, wird dann evtl. auf openMP zurückgegriffen - zumindest einfache Sachen wie die ganzen Schleifen - scheinen damit ja sehr einfach zu gehen. Oder es wird eine Mischung mit dem Besten aus beiden Welten? Egal, jetzt weiss ich um ihre Existenz und kann im Fall der Fälle darauf zurückgreifen, danke auch für deine openMP-Version.

Darf man fragen, wofür du 16 cores brauchst? Ich nehme jetzt mal frech an, dass man sich nicht wegen Battlefield 3 oder Skyrim zwei Octacores zulegt...


edit: und ein core braucht nur 15 Sekunden für x*x seriell? was für ein Monster ist das? :D

@maxwell-cs

grad gegoogelt, mal anschauen, danke dir
 
Zuletzt bearbeitet:
mahatma andi schrieb:
Darf man fragen, wofür du 16 cores brauchst? Ich nehme jetzt mal frech an, dass man sich nicht wegen Battlefield 3 oder Skyrim zwei Octacores zulegt...
Entweder er hat Anwendungen, die die Rechenleistung brauchen (Enkodieren, Simulationen usw.) oder er entwickelt auch für Multi-Core Anwendungen, da kann man nie genug Kerne haben um Bottlenecks aufzuspüren.
 
maxwell-cs schrieb:
frag doch mal callgrind.

Ja, ok, hab ich. Dann noch das tolle (?) Programm Kcachegrind heruntergeladen zur Visualisierung das sieht dann etwa so aus:
Screenshot%20from%202012-08-17%2021%3A08%3A22.png

LINK

Nun, ich habe keine Ahnung was das bedeuten soll. Jetzt bräuchte ich noch eine weisende Hand, die mir sagt, wo ich herausfinden kann (am besten im grösseren Zusammenhang), was Ir und DLmw oder Data Read Miss bedeuten.
Das ganze ist mir momentan weniger verständlich als Ungarisch...

edit; ok, gerade das gefunden:
Screenshot%20from%202012-08-17%2021%3A23%3A38.png

LINK

Das sagt doch schon mehr aus...
Bevor sich jemand die Finger wund schreibt, ich such noch ein wenig nach Infos rum, glaube, da bekomme ich auch alleine ein wenig zu stande :)

EDIT: sind nur 1000 Iterationen von fvalue, deshalb der vergleichsweise gigantische Wert von mt_init.
 
Zuletzt bearbeitet:
Zurück
Oben