Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione realme 16 5G: lo smartphone con Selfie Mirror ha una batteria da 6550mAh
Recensione realme 16 5G: lo smartphone con Selfie Mirror ha una batteria da 6550mAh
realme 16 5G è un nuovo smartphone con sensore Sony IMX 852 da 50MP sul retro e uno specchio selfie fisico integrato nella camera bar, una prima nel segmento di mercato. Batteria da 6550mAh in un corpo da 8,1mm e 183g, certificazione IP69K e ricarica da 45W completano un pacchetto aggressivo per la fascia media, per uno dei prodotti più interessanti del produttore sul piano commerciale
Come rispettare tutte le nuove regole per i monopattini elettrici? La guida per non rischiare sanzioni
Come rispettare tutte le nuove regole per i monopattini elettrici? La guida per non rischiare sanzioni
Sono ormai definitive le nuove norme del Codice della Strada per i monopattini elettrici. Non solo targa e assicurazione, le regole sono tante e riguardano diversi aspetti, vi spieghiamo come evitare sanzioni che possono essere salate
DLSS 4.5: con Dynamic Frame Generation e MFG 6X NVIDIA alza la posta
DLSS 4.5: con Dynamic Frame Generation e MFG 6X NVIDIA alza la posta
DLSS 4.5 introduce Dynamic Multi Frame Generation e MFG 6X, permettendo fino a cinque frame generati per ogni frame renderizzato. I test su Cyberpunk 2077 e 007 First Light mostrano forti incrementi di FPS e riduzione della latenza su RTX 5090 Laptop. Migliorano fluidità, stabilità e qualità visiva.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 15-11-2011, 21:11   #1
Pegasus84
Senior Member
 
L'Avatar di Pegasus84
 
Iscritto dal: Nov 2008
Città: Napoli
Messaggi: 846
[C] - Una domanda sui threads...

Salve a tutti!

Vorrei porre un quesito a tutti voi, dato che io non capisco: può capitare che aumentando il numero di threads, ad esempio da 4 threads a 5, l'esecuzione di un codice parallelo possa vedere leggermente degradate le proprie prestazioni per poi tornare a migliorare? Perché?

Qualcuno mi sa illuminare? E' una cosa che mi fa sclerare...
Pegasus84 è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2011, 22:27   #2
Cait Sith
Senior Member
 
L'Avatar di Cait Sith
 
Iscritto dal: Apr 2005
Messaggi: 309
Per dare una risposta con cognizione di causa si dovrebbe sapere come è fatto il programma e che cosa fanno i singoli thread.
Comunque dipende anche dal numero di core del processore: se hai 4 core, 5 thread che occupano le stesse risorse hardware (per esempio l'unità floating point) non credo che aiutino a migliorare le performance di un programma.
Cait Sith è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2011, 22:37   #3
Pegasus84
Senior Member
 
L'Avatar di Pegasus84
 
Iscritto dal: Nov 2008
Città: Napoli
Messaggi: 846
Intel® Xeon® Processor E5410 ha 4 cores, quindi se passa da 4 a 5, peggiora leggermente le prestazioni per poi tornare a migliorare...

Comunque un programma semplice che ho collaudato effettua la somma di N numeri double su un sistema con shared memory... Utilizzando OpenMP, ovviamente...
Pegasus84 è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2011, 22:43   #4
Cait Sith
Senior Member
 
L'Avatar di Cait Sith
 
Iscritto dal: Apr 2005
Messaggi: 309
Probabilmente paghi l'overhead di openmp: fai conto che la creazione di regioni parallele ha un costo, come pure la schedulazione e l'evenutale sincronizzazione dei thread. Se non si hanno beneficio nello sfruttamente dell'hardware, non vale la pena aprire thread in più.

Ultima modifica di Cait Sith : 15-11-2011 alle 22:51.
Cait Sith è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2011, 23:07   #5
Pegasus84
Senior Member
 
L'Avatar di Pegasus84
 
Iscritto dal: Nov 2008
Città: Napoli
Messaggi: 846
Quote:
Originariamente inviato da Cait Sith Guarda i messaggi
Probabilmente paghi l'overhead di openmp: fai conto che la creazione di regioni parallele ha un costo, come pure la schedulazione e l'evenutale sincronizzazione dei thread. Se non si hanno beneficio nello sfruttamente dell'hardware, non vale la pena aprire thread in più.
Questo è il mio codice...

Codice:
	int main (int argc, char *argv[])
{
	int 	i, N, nthreads, tid, nloc, nloc_threads, rest;
	double 	*x, sumtot=0.0;

	/* Converte in int il numero di threads da utilizzare inserito dall'utente */
	sscanf (argv[1], "%d", &nthreads);
	/* Converte in int il numero di reali da generare casualmente inserito dall'utente */
	sscanf (argv[2], "%d", &N);

	/* Setta il numero di threads da utilizzare inserito dall'utente */
	omp_set_num_threads(nthreads);

	x = (double *)calloc(N,sizeof(double));

	srand(time(NULL));
	for (i=0; i<N; i++)
		x[i] = 100.0 * (double) rand() / (double) 0x7fffffff;
	
	/* Calcolo del numero di addendi da assegnare ad ogni thread */
	nloc_threads=N/nthreads;
	rest=N%nthreads;
	/* In caso affermativo: incremento del numero di addendi ottenuti */
	if ( rest!=0 )
		nloc=nloc_threads+1;
	else /* In caso negativo */
		nloc=nloc_threads;

	#pragma omp parallel
	somma( x, &sumtot, nloc, N );
	printf ("\nLa somma totale e' %lf\n\n", sumtot);
	/* Deallocazione memoria */
	free(x);
	
return 0;
}


	void somma ( double *x, double *sumtot, int nloc, int N )
{
	/* Variabili */
	int	i, tid;
	double	sum=0.0;

	/* Ricava l'identificativo del thread corrente */
	tid = omp_get_thread_num();

	#pragma omp private (sum, nloc, i) shared(*sumtot)
  	{
		sum=0;
		for (i=0; i<nloc; i++)
			sum=sum+x[i+nloc*tid];
		//printf("Sono il thread %d - Somma parziale %lf\n", tid, sum);
		#pragma omp critical
			(*sumtot)+=sum;
	}
}
Che ne pensi della mia idea di somma?

Ma poi secondo me non ha senso provare con 1-2-3-4-5-6-7-8 threads... Mi pare più corretto provare con una potenza di 2 del numero di threads, cioè 1-2-4-8... O sbaglio?

Ultima modifica di Pegasus84 : 15-11-2011 alle 23:16.
Pegasus84 è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2011, 23:50   #6
Cait Sith
Senior Member
 
L'Avatar di Cait Sith
 
Iscritto dal: Apr 2005
Messaggi: 309
Non è che stavo dicendo che il tuo programma può essere scritto meglio, ma che quando il numero di thread supera il numero di core fisici, non è così strano che le prestazioni non aumentino o addirittura diminuiscano. Se lanci con 200 thread sarà ancora peggio.
Poi che i thread siano o non siano potenze di due non credo c'entri molto. Su 4 core sono sicuramente meglio 3 thread rispetto a 2.

Il tuo programma l'ho guardato velocemente e non mi torna la variabile nloc. Se ho 4 thread e 7 addendi, nloc non può essere uguale per tutti i thread perchè vorrebbe dire che sommo 2 addendi ogni thread per un totale di 8. Del resto nloc non può nemmeno essere diverso per i vari thread perchè lo usi per costruire l'offset dell'array nella somma. Così com'è si rischia un segmentation fault (se il numero di thread è piccolo difficilmente si verificherà).
Ti conviene usare come stride il numero totale di thread, come indice iniziale del ciclo l'indice del thread e fare:
Codice:
for(k=tid;k<N;k+=Nthreads) sum+=x[k];
Con a seguire il blocco critico. In questo modo non ti devi preoccupare di quali thread devono sommare un elemento in meno degli altri nel caso ci sia il resto.


Poi la direttiva
Codice:
#pragma omp private (sum, nloc, i) shared(*sumtot)
non credo che serva perchè sum, loc e i sono state allocate nello stack della funzione che a sua volta è stata chiamata da ogni singolo thread (quindi ogni thread ha il suo stack), e sumtot, anche se è allocato in stack diversi punta sempre alla stessa variabile

Ultima modifica di Cait Sith : 15-11-2011 alle 23:53.
Cait Sith è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2011, 00:12   #7
Pegasus84
Senior Member
 
L'Avatar di Pegasus84
 
Iscritto dal: Nov 2008
Città: Napoli
Messaggi: 846
Quote:
Originariamente inviato da Cait Sith Guarda i messaggi
Non è che stavo dicendo che il tuo programma può essere scritto meglio, ma che quando il numero di thread supera il numero di core fisici, non è così strano che le prestazioni non aumentino o addirittura diminuiscano. Se lanci con 200 thread sarà ancora peggio.
Poi che i thread siano o non siano potenze di due non credo c'entri molto. Su 4 core sono sicuramente meglio 3 thread rispetto a 2.
Hai ragione...

Quote:
Originariamente inviato da Cait Sith Guarda i messaggi
Il tuo programma l'ho guardato velocemente e non mi torna la variabile nloc. Se ho 4 thread e 7 addendi, nloc non può essere uguale per tutti i thread perchè vorrebbe dire che sommo 2 addendi ogni thread per un totale di 8. Del resto nloc non può nemmeno essere diverso per i vari thread perchè lo usi per costruire l'offset dell'array nella somma. Così com'è si rischia un segmentation fault (se il numero di thread è piccolo difficilmente si verificherà).
Ti conviene usare come stride il numero totale di thread, come indice iniziale del ciclo l'indice del thread e fare:
Codice:
for(k=tid;k<N;k+=Nthreads) sum+=x[k];
Con a seguire il blocco critico. In questo modo non ti devi preoccupare di quali thread devono sommare un elemento in meno degli altri nel caso ci sia il resto.
In effetti anche qui hai ragione: pensandoci bene neanche io mi trovo con nloc... Ho seguito il tuo consiglio e funziona benissimo...

Quote:
Originariamente inviato da Cait Sith Guarda i messaggi
Poi la direttiva
Codice:
#pragma omp private (sum, nloc, i) shared(*sumtot)
non credo che serva perchè sum, loc e i sono state allocate nello stack della funzione che a sua volta è stata chiamata da ogni singolo thread (quindi ogni thread ha il suo stack), e sumtot, anche se è allocato in stack diversi punta sempre alla stessa variabile
Forse la direttiva serve solo per sumtot dichiarandola variabile condivisa, perché comunque devo fare la somma totale prendendo le somme parziali dei threads vari...

Ti ringrazio tanto! Mi hai chiarito molte idee e mi hai anche fatto snellire il codice con i tuoi suggerimenti! Un grazie tante ancora!

Un'altra domanda: ma se ho 4 core fisici ed 8 threads, è normale lo stesso se da 4 a 5 threads peggiora lievemente come prestazioni per poi tornare a crescere? Da 2 a 3, invece, mi trovo!
Pegasus84 è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2011, 10:28   #8
Cait Sith
Senior Member
 
L'Avatar di Cait Sith
 
Iscritto dal: Apr 2005
Messaggi: 309
La direttiva shared di solito è sottintesa. Tieni conto che, non puoi rendere privata un'area di memoria puntata da un puntatore. Se hai un vettore
Codice:
float *x;
x=calloc(10,sizeof(float));
Tu puoi rendere privato l'indirizzo, ovvero il contenuto della variabile x, ma non l'area puntata da x (gli elementi x[0],x[1],x[2]).

Per quanto riguarda i core fisici e logici, penso dipenda, come avevo accennato, alle risorse che utilizzano i thread. Non sono un esperto quindi non prendermi alla lettera, ma penso che l'unità floating point difficilmente si riesce a condividere in modo ottimale tra due thread che girano sullo stesso core. Se vuoi fare esperimenti prova a fare la somma di interi anzichè di double, magari lì si nota il guadagno dell'hyperthreading.

Ultima modifica di Cait Sith : 16-11-2011 alle 10:31.
Cait Sith è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2011, 16:18   #9
Pegasus84
Senior Member
 
L'Avatar di Pegasus84
 
Iscritto dal: Nov 2008
Città: Napoli
Messaggi: 846
Quote:
Originariamente inviato da Cait Sith Guarda i messaggi
La direttiva shared di solito è sottintesa. Tieni conto che, non puoi rendere privata un'area di memoria puntata da un puntatore. Se hai un vettore
Codice:
float *x;
x=calloc(10,sizeof(float));
Tu puoi rendere privato l'indirizzo, ovvero il contenuto della variabile x, ma non l'area puntata da x (gli elementi x[0],x[1],x[2]).
Questo perché è comunque un puntatore, giusto? Mentre nella realtà la variabile vera e propria NON è privata? Ho capito bene?

Comunque alla fine ho deciso di togliere la funzione somma e posizionare il suo corpo direttamente nel main, come segue:

Codice:
/* Viene creato un "team" di threads che provvederanno a sommare simultaneamente */
	#pragma omp parallel private (sum, i, tid) shared (sumtot)
	{
		/* Ricava l'identificativo del thread corrente */
		tid = omp_get_thread_num();
		
		for (i=tid; i<N; i+=nthreads)
		{
			sum+=x[i];
			printf ("Sono il thread %d - x[%d] = %lf\n", tid, i, x[i]);
		}
	
		printf("Sono il thread %d - Somma parziale %lf\n", tid, sum);
		
		#pragma omp critical
			sumtot+=sum;
	}
In questo modo evito incoerenze riguardo l'uso del puntatore sumtot nelle direttive omp...

Ultima modifica di Pegasus84 : 16-11-2011 alle 17:04.
Pegasus84 è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2011, 19:36   #10
Cait Sith
Senior Member
 
L'Avatar di Cait Sith
 
Iscritto dal: Apr 2005
Messaggi: 309
Per curiosità ho provato a compilare (con gcc) un codice con
Codice:
#pragma omp parallel shared(* var)
e mi da un warning perchè non riconosce *, non so come fai a compilare.
Secondo me nella lista di variabili non puoi mettere asterischi per la deferenziazione di puntatori
Comunque già che c'ero ho verificato che gli array allocati staticamente, li puoi rendere privati, mentre gli array allocati dinamicamente ovviamente no.
Spero di chiarire con il seguente esempio:
Codice:
float x_sta[1];
float *x_din;
x_din=calloc(1,sizeof(float));
#pragma omp parallel private(x_sta,x_din)
{
    x_sta[0]=omp_get_thread_num(); // questo elemento dell'array è privato per ogni thread
    x_din[0]=omp_get_thread_num(); // questo elemento dell'array è condiviso dai thread, quindi qui si verifica una race condition se non si mette blocco critico
    x_din=calloc(1,sizeof(float)); // sovrascrivo il puntatore x_din, che è privato, con l'indirizzo di una nuova area di memoria allocata, che è diversa per ogni thread (quindi ho Nthread allocazioni)
    x_din[0]=omp_get_thread_num(); // questo elemento dell'array, è diverso per ogni thread, perchè ora l'x_din di ogni thread punta a diverse aree di memoria, quindi qui non ci sono race condition
}
Cait Sith è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2011, 19:53   #11
Pegasus84
Senior Member
 
L'Avatar di Pegasus84
 
Iscritto dal: Nov 2008
Città: Napoli
Messaggi: 846
Quote:
Originariamente inviato da Cait Sith Guarda i messaggi
Per curiosità ho provato a compilare (con gcc) un codice con
Codice:
#pragma omp parallel shared(* var)
e mi da un warning perchè non riconosce *, non so come fai a compilare.
Secondo me nella lista di variabili non puoi mettere asterischi per la deferenziazione di puntatori
Comunque già che c'ero ho verificato che gli array allocati staticamente, li puoi rendere privati, mentre gli array allocati dinamicamente ovviamente no.
Spero di chiarire con il seguente esempio:
Codice:
float x_sta[1];
float *x_din;
x_din=calloc(1,sizeof(float));
#pragma omp parallel private(x_sta,x_din)
{
    x_sta[0]=omp_get_thread_num(); // questo elemento dell'array è privato per ogni thread
    x_din[0]=omp_get_thread_num(); // questo elemento dell'array è condiviso dai thread, quindi qui si verifica una race condition se non si mette blocco critico
    x_din=calloc(1,sizeof(float)); // sovrascrivo il puntatore x_din, che è privato, con l'indirizzo di una nuova area di memoria allocata, che è diversa per ogni thread (quindi ho Nthread allocazioni)
    x_din[0]=omp_get_thread_num(); // questo elemento dell'array, è diverso per ogni thread, perchè ora l'x_din di ogni thread punta a diverse aree di memoria, quindi qui non ci sono race condition
}
Hai provato a compilare nel seguente modo:

Codice:
gcc -fopenmp -lgomp -o eseguibile codice.c
?

A me compila correttamente senza warning...

Tuttavia, se il vettore lo fai condividere a tutti i threads, solo in lettura, non accade nessuna race condition, o erro? Sei d'accordo? Mmmmm, ma non è che si debba mettere la direttiva omp critical dove i threads fanno le somme parziali, cioè dove c'è il ciclo seguente:


Codice:
for (i=tid; i<N; i+=nthreads)
		{
			sum+=x[i];
			printf ("Sono il thread %d - x[%d] = %lf\n", tid, i, x[i]);
		}
Ma penso che sia inutile, perchè sul vettore non viene eseguita alcuna operazione di scrittura... Alla fine non credo che nel caso della sola lettura si possano produrre race conditions...

Ultima modifica di Pegasus84 : 16-11-2011 alle 20:00.
Pegasus84 è offline   Rispondi citando il messaggio o parte di esso
Old 20-11-2011, 19:54   #12
Cait Sith
Senior Member
 
L'Avatar di Cait Sith
 
Iscritto dal: Apr 2005
Messaggi: 309
in effetti ho compilato con -fopenmp ma senza mettere -lgomp, però il programma mi sembra funzioni quando lo compilo

una race condition si verifica solo quando più thread tentano di scrivere un elemento di memoria condiviso, in lettura non ci sono mai problemi

il sum non lo devi mettere nel blocco critical perchè la variabile è privata, quindi ogni thread aggiorna la sua copia, altrimenti la variabile sum non servirebbe, ma agiresti direttamente su sumtot
è solo alla fine, quando calcoli la somma totale, che devi usare un blocco critical
Cait Sith è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Recensione realme 16 5G: lo smartphone con Selfie Mirror ha una batteria da 6550mAh Recensione realme 16 5G: lo smartphone con Selfi...
Come rispettare tutte le nuove regole per i monopattini elettrici? La guida per non rischiare sanzioni Come rispettare tutte le nuove regole per i mono...
DLSS 4.5: con Dynamic Frame Generation e MFG 6X NVIDIA alza la posta DLSS 4.5: con Dynamic Frame Generation e MFG 6X ...
Plaud NotePin S, il registratore IA si fa indossabile (ma è facile da perdere) Plaud NotePin S, il registratore IA si fa indoss...
Redmi Watch 6 in prova: lo smartwatch con ampio display da 2000 nit a meno di 100 euro Redmi Watch 6 in prova: lo smartwatch con ampio ...
Vertiv: data center, la corsa dell’IA sp...
Siri non diventerà la tua fidanzata virt...
Prezzi in crescita del 200% e forniture ...
Ancora non lo sai, ma il 'botsitting' ti...
L'IA costringe a velocizzare lo sviluppo...
NVIDIA l'ha tenuta nascosta per anni: sp...
Più smartphone, meno fiki fiki: l...
CrossOver taglia i ponti con Intel: il t...
Ancora doppio sconto sulla Engwe pi&ugra...
Pezzotto, scatta maxi sequestro da 650.0...
Ecco come acquistare EA FC 26 a 18€: gio...
Google: un nuovo speaker smart da 99 dol...
Un tessuto innovativo può raccogl...
Uno YouTuber vuole denunciare Samsung: l...
Pokémon Go utilizzato per addestrare i d...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 13:50.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v