DualCore - Prozess einem Kern zuweisen

Hallo,
Hi,
ich habe jetzt vom Prof. ein weiteres Beispiel bekommen. Dort funktioniert es. Ich habe ein Array und berechne die obere und untere Hälfte in jeweils zwei Threads. Hier ist das Progamm ca 1,9x so schnell ;)
wie sieht das Programm denn aus? Werden die zwei Hälften des Arrays unabhängig von den 2 Threads berechnet? Ich denke mal das du da ohne Synchronisation auskommst, oder? Kann man von deinem Seminar eigtl. was bestaunen(also so Folientechnisch), würde mich selbst mal intressieren ...

Gruß,
RedWing
 
Ich muss ein Referat und eine Arbeit zum Thema: "Aufgaben eines Mehrprozessorfähigen Betriebssystems" schreiben.

odd & even kannst hier ignorieren. Ist nicht so gut, wegen der Cache-Kohärenz. Lieber das Array halbieren, als gerade & ungerade berechnen.
Ich bekomm das aber mit dem dritten Thread nicht hin :(

Code:
#include <thread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <sys/errno.h>
#include <sys/processor.h>
#include <sys/procset.h>
#define CACHE_LINE_SIZE 32
#define DIV_NUMBER 114
#define CPU_ID_A 3
#define CPU_ID_B 4

static float* array1;
static float* array2;
int size;
int loop;

void *process_even(void* threadid);
void *process_odd(void* threadid);
void *process_lower(void* threadid);
void *process_upper(void* threadid);
void wrong_input(void);



int main (int argc, char *argv[])
{
	int rc, t;
	long t1,t2;
	char type;
	t1 = 0;
	t2 = 0;
	

	if(argc < 4)
		wrong_input();

	type = argv[1][0];
	size = atoi(argv[2]);
	loop = atoi(argv[3]);

	if((type != '1')&&(type != '0')||(size <= 0)||(loop <= 0)||(size%2 != 0))
		wrong_input();

	/* Speicherreservierung. valloc reserviert Speicher am Block Anfang.
	Mit dif wird der reservierte Speicher auf ein exaktes vielfaches der Cache-Line größe erweitert */

	int dif = CACHE_LINE_SIZE-( (size*sizeof(float) )%CACHE_LINE_SIZE);
	array1 = valloc(dif+size*sizeof(float));
	array2 = valloc(dif+size*sizeof(float));

	/* init array */
	int i;
	for(i = 0; i< size; i++){
		array1[i] = (float)i;
		array2[i] = (float)i;
	}
	t = 0;
	pthread_t thread_even;
	pthread_t thread_odd;
	pthread_t thread_upper;
	pthread_t thread_lower;

	t1 = clock();

	/* Berechnung EVEN / ODD */
	if(type == '1'){
		rc = pthread_create(&thread_even, NULL, process_even,(void *)t);
		if (rc){
			printf("ERROR; return code from pthread_create() is %d\n", rc);
       		exit(1);
		}

		process_odd(&t);
		rc = pthread_join(thread_even, NULL); /* Auf thread warten */
	}

	/* Berechnung UPPER / LOWER */
	else if(type == '0'){
		rc = pthread_create(&thread_upper, NULL, process_upper,(void *)t);
		if (rc){
       		printf("ERROR; return code from pthread_create() is %d\n", rc);
			exit(-1);
		}

		process_lower(&t);
		rc = pthread_join(thread_upper, NULL); /* Auf thread warten */
	}
		t2 = clock();
		if(type == '1')
			printf("\nType: Even/Odd");
		else
			printf("\nType: Upper/Lower");

		printf("\nTime: %d,  size: %d,  loop: %d\n\n", (t2-t1)/1000, size, loop);
	
	pthread_exit(NULL);
}


/* Berechnen der geraden Einträge */
void *process_even(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID, 2, NULL);
assert(ret == 0);
printf("\nCpu_id: %d", getcpuid());*/

int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = 0; i < size; i = i+2)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}

/* Berechnen der ungeraden Einträge */
void *process_odd(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID, 6, NULL);
assert(ret == 0);
printf("\nCpu_id: %d", getcpuid());*/

int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = 1; i < size; i = i+2)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}

/* Berechnen der ersten Hälfte der arrays */
void *process_upper(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID, 2, NULL);
assert(ret == 0);
printf("\nCpu_id: %d", getcpuid());*/

int upper_end = (size/2) -1;

int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = 0; i < upper_end; i++)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}


/* Berechnen der zweiten Hälfte der arrays */
void *process_lower(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID,6, NULL);
assert(ret == 0); 
printf("\nCpu_id: %d", getcpuid());*/

int lower_start = size/2;
int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = lower_start; i < size; i++)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}


void wrong_input(){
	printf("\nWrong argument count!\n");
	printf("\nArg1: type 0 = upper/lower, 1 = even/odd");
	printf("\nArg2: array size (number of floats). Size modulo 2 must be 0.");
	printf("\nArg3: loop count");
	exit(0);
}

Hier mein Ansatz:
Code:
/* Berechnen der ersten H?lfte der arrays */
void *process_upper(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID, 2, NULL);
assert(ret == 0);
printf("\nCpu_id: %d", getcpuid());*/

int upper_end = (size/3) -1;

int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = 0; i < upper_end; i++)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}


/* Berechnen des Mittleren Arrays */
void *process_middle(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID,6, NULL);
assert(ret == 0); 
printf("\nCpu_id: %d", getcpuid());*/

int middle_start = size/3;
int lower_end = ((size/3)*2) -1;
int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = middle_start; i < lower_end; i++)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}


/* Berechnen der dritten H?lfte der arrays */
void *process_lower(void* threadid){
/*int ret = processor_bind(P_LWPID, P_MYID,6, NULL);
assert(ret == 0); 
printf("\nCpu_id: %d", getcpuid());*/

int lower_start = (size/3)*2;
int i, inner_l;
for(inner_l = 0; inner_l < loop; inner_l++)
	for(i = lower_start; i < size; i++)
		array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}
 
Also spontan fällt mir auf das du immer ein Element auslässt...
Ich denke so ists richtig:

C:
/* Berechnen der ersten H#lfte der arrays */
void *process_upper(void* threadid){
    /*int ret = processor_bind(P_LWPID, P_MYID, 2, NULL);
      assert(ret == 0);
      printf("\nCpu_id: %d", getcpuid());*/

    int upper_end = (size/3);

    int i, inner_l;
    printf("Starting at %d Ending at %d\n", 0, upper_end);
    for(inner_l = 0; inner_l < loop; inner_l++)
        for(i = 0; i < upper_end; i++)
            array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}

/* Berechnen des Mittleren Arrays */
void *process_middle(void* threadid){
    /*int ret = processor_bind(P_LWPID, P_MYID,6, NULL);
      assert(ret == 0); 
      printf("\nCpu_id: %d", getcpuid());*/

    int middle_start = size/3;
    int lower_end = (size/3)*2;
    int i, inner_l;
    printf("Starting at %d Ending at %d\n", middle_start, lower_end);
    for(inner_l = 0; inner_l < loop; inner_l++)
        for(i = middle_start; i < lower_end; i++)
            array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}

/* Berechnen der dritten H#lfte der arrays */
void *process_lower(void* threadid){
    /*int ret = processor_bind(P_LWPID, P_MYID,6, NULL);
      assert(ret == 0); 
      printf("\nCpu_id: %d", getcpuid());*/

    int lower_start = (size/3)*2;
    int i, inner_l;
    printf("Starting at %d Ending at %d\n", lower_start, size);
    for(inner_l = 0; inner_l < loop; inner_l++)
        for(i = lower_start; i < size; i++)
            array1[i] = (array1[i] + array2[i]) / DIV_NUMBER;
}

Gruß,
RedWing
 
Ich lass kein Element aus
oben: 0 bis i-1
mitte: i bis k -1
unten: k bis ende

Deine Variante läuft trotzdem 2x so schnell, genauso wie bei mir :(
 
Ich lass kein Element aus
oben: 0 bis i-1
mitte: i bis k -1
unten: k bis ende
Nat. läßt du eins aus. Wenn du mir nicht glaubst schau mal auf deinen end_wert( der is nämlich jeweils i -1 bis auf den letzten Endwert size) und auf deine Schleifenbedingung (welche immer < anstatt <= ist). => du gehst nicht bis i-1 sondern bis i -2 und fängst im nächsten bei i wieder an => du hast ein Element ausgelassen.

Deine Variante läuft trotzdem 2x so schnell, genauso wie bei mir :(

Ja hab ja auch nichts sonst weiter dran geändert.


Gruß,
RedWing
 
Zuletzt bearbeitet:
Nat. läßt du eins aus. Wenn du mir nicht glaubst schau mal auf deinen end_wert( der is nämlich jeweils i -1 bis auf den letzten Endwert size) und auf deine Schleifenbedingung (welche immer < anstatt <= ist). => du gehst nicht bis i-1 sondern bis i -2 und fängst im nächsten bei i wieder an => du hast ein Element ausgelassen.
Stimmt, verzeih mir ;)
Ich sitzt heut schon wieder zulange vorm Rechner ;(

Ja hab ja auch nichts sonst weiter dran geändert.
Wo liegt dann noch der Fehler?
 
Stimmt, verzeih mir ;)
Ich sitzt heut schon wieder zulange vorm Rechner ;(
Kein Problem, kann ich verstehen :)

Wo liegt dann noch der Fehler?
Hast du denn den 3ten Thread auch gestartet? Also in deinem Code kann man davon nämlich nichts sehen.
Falls doch, weiß ichs auch nicht, dazu kenn ich die "Linux Internals" insbesondere den Load Balancer vom Scheduler (das is der Teil des Linux Kernels der für die Aufteilung der Prozesse auf die versch. CPUs zuständig ist) zu wenig. Aber vlt. solltest du dir das mal anschauen, wie Linux das Intern macht, das könnte auch für dein Seminar hilfreich sein. EIn Buch wo das sehr gut beschrieben ist (wenn du denn noch Zeit hast) ist das vom Robert Love (Linux Kernelhandbuch), oder du schaust mal bei google.

Gruß,
RedWing
 
Hast du denn den 3ten Thread auch gestartet?

Eigentlich ja... :confused:

Inwieweit muss ich den dritten Thread bei der Berechnung mit einbauen?
Code:
/* Berechnung UPPER / LOWER */
	else if(type == '0'){
		rc = pthread_create(&thread_upper, NULL, process_upper,(void *)t);
		if (rc){
       		printf("ERROR; return code from pthread_create() is %d\n", rc);
			exit(-1);
		}

		process_lower(&t);
		rc = pthread_join(thread_upper, NULL); /* Auf thread warten */
	}
 
Mhm also starten würdest du ihn so:
C:
...
pthread thread_middle;
...
rc = pthread_create(&thread_upper, NULL, process_upper,(void *)t);
if (rc){
	printf("ERROR; return code from pthread_create() is %d\n", rc);
	exit(-1);
}

rc = pthread_create(&thread_middle, NULL, process_middle,(void *)t);
if (rc){
	printf("ERROR; return code from pthread_create() is %d\n", rc);
	exit(-1);
}
process_lower(&t);
rc = pthread_join(thread_upper, NULL); /* Auf upper thread warten */
rc = pthread_join(thread_middle, NULL); /* Auf middle thread warten (falls noch nicht fertig) */

Gruß,
RedWing
 
Jetzt siehts schonmal gut aus.
Die Zeiten auf 2 Kerne variieren! Das Prog läuft ca. 1,7-1,9x schneller
Wobei mir die 1,9 schon recht hoch erscheint

Auf einem Kern sind die Zeiten fast identisch
 

Neue Beiträge

Zurück