Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Insta360 Luna Ultra: la potenza del sensore da 1 pollice incontra la portabilità estrema
Insta360 Luna Ultra: la potenza del sensore da 1 pollice incontra la portabilità estrema
Insta360 Luna Ultra integra un sensore da 1 pollice 8K, ottiche Leica e triplo chip IA. Tra schermo OLED rimovibile, workflow I-Log a 10 bit e stabilizzazione a tre assi, analizziamo le doti tecniche di una gimbal camera pensata per i professionisti
Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa
Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa
Marvel's Wolverine porta Logan in un'avventura inedita, violenta e fortemente narrativa, costruita attorno alla sua natura di combattente e al difficile rapporto con il proprio passato. Insomniac Games punta su combattimenti spettacolari, progressione e personalizzazione, inserendo l'azione in un mondo segnato dalla persecuzione dei mutanti. Un viaggio intenso, che alterna mattanza, esplorazione e momenti sorprendentemente emotivi.
DJI Romo 2: tante novità lo rendono un robot completo
DJI Romo 2: tante novità lo rendono un robot completo
Romo 2 è la seconda generazione di robot lavapavimenti di DJI, un modello che si caratterizza per la precisione nel sistema di navigazione e per il funzionamento particolarmente silenzioso. Con le modifiche introdotte in questa seconda versione, e un posizionamento di prezzo più allineato alla concorrenza, rappresenta una valida alternativa sul mercato delle soluzioni di pulizia domestica
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 10-05-2011, 11:28   #1
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
[C] - Performance

Supponiamo di avere una funzione molto semplice che mi permette di copiare byte a byte passando come parametro due puntatori e la dimensione.. una cosa del tipo

Codice:
void mcpy(void *src, void *dst, unsigned size){
	int i = 0;
	do{
		*((char*)dst + i) = *((char*)src + i);
	}while(++i < size);
}
questa funziona bene... se la ripeto per parecchie-mila volte ci mette un po troppo tempo....
ad esempio la ripeto per 100000000 volte impiega circa 6.5 secondi su un core due duo da 2GHz
ma comunque non mi interessa tanto questa faccenda, o almeno non mi interessa ora

passo il tutto a Instruments e ho come risultato questo



il 22.7% è utilizzato solo per l'incremento e il controllo della variabile..
a me sembra molto... come posso rendere più veloce questa cosa

inoltre se volessi andare sul discorso dei tempi...
la funzione memcpy della libreria string.h sullo stesso input e con lo stesso numero di cicli impiega circa 2 secondi... in che modo copia i valori?

Il tutto ovviamente ha uno scopo didattico, nel senso che non mi importa tanto di quella funzione, ma di come far diventare più efficiente ogni tipo di codice
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 13:05   #2
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Quote:
Originariamente inviato da clockover Guarda i messaggi
Supponiamo di avere una funzione molto semplice che mi permette di copiare byte a byte passando come parametro due puntatori e la dimensione.. una cosa del tipo

Codice:
void mcpy(void *src, void *dst, unsigned size){
	int i = 0;
	do{
		*((char*)dst + i) = *((char*)src + i);
	}while(++i < size);
}
questa funziona bene... se la ripeto per parecchie-mila volte ci mette un po troppo tempo....
ad esempio la ripeto per 100000000 volte impiega circa 6.5 secondi su un core due duo da 2GHz
ma comunque non mi interessa tanto questa faccenda, o almeno non mi interessa ora

passo il tutto a Instruments e ho come risultato questo



il 22.7% è utilizzato solo per l'incremento e il controllo della variabile..
a me sembra molto... come posso rendere più veloce questa cosa

inoltre se volessi andare sul discorso dei tempi...
la funzione memcpy della libreria string.h sullo stesso input e con lo stesso numero di cicli impiega circa 2 secondi... in che modo copia i valori?

Il tutto ovviamente ha uno scopo didattico, nel senso che non mi importa tanto di quella funzione, ma di come far diventare più efficiente ogni tipo di codice

Controlla se migliori con
Codice:
void mcpy(void *src, void *dst, unsigned size){
	int i = 0;
	do{
		*dst++ = *src++;
	}while(++i < size);
}
Sui vecchi processori migliorava le prestazioni.

Un altro modo per migliorare e' usare meglio il bus dati... (detto in altri termini: copiare NON un char ma qualcosa di piu' grande di un bytes)
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 14:58   #3
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Come mi hai consigliato tu c'è un notevole miglioramento (a livello di tempi),
ora ci impiega meno di 4 secondi per lo stesso numero di operazioni



però a maggior ragione adesso è ancora più inaccettabile il consumo di risorse del controllo della variabile.. si può fare di meglio anche li?
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 15:29   #4
british
Member
 
L'Avatar di british
 
Iscritto dal: Sep 2008
Città: Milano
Messaggi: 126
come curiosità didattica, prova a guardare questo:
http://en.wikipedia.org/wiki/Duff%27s_device


ciao!

british
british è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 15:43   #5
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Loop unrolling... quindi è l'unico modo per ridurre al minimo i controlli e l'incremento della variabile.. In effetti ho fatto una cosa del genere (sempre per delle prove) in questo modo



e infatti il tempo perso nel controllo del while è minimo ora... ora provo altre soluzioni

edit
non sto usando nessun livello di ottimizzazione
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 16:10   #6
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 13043
Provo a dire la mia... hai provato a castare i puntatori fuori dal ciclo, anziché farlo ad ogni passo?
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 16:11   #7
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Quote:
Originariamente inviato da WarDuck Guarda i messaggi
Provo a dire la mia... hai provato a castare i puntatori fuori dal ciclo, anziché farlo ad ogni passo?
Grande e chi ci aveva pensato... ci provo subito
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 16:35   #8
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Ho tentato un'altra strada per vedere la situazione come va e ho anche ascoltato il suggerimento di WarDuck

Codice:
void mcpyF2(void *src, void *dst, unsigned size){
	unsigned i = 0;
	unsigned max = 0;
	unsigned resto = size % 8;
	char *Dc = (char*)dst;
	char *Sc = (char*)src;
	switch (resto) {
		case 0:
			max = size - 7;
			double *Dd = (double*)dst;
			double *Sd = (double*)src;
			do{
				*(Dd++) = *(Sd++);
				i += 8;
			}while(i < max);
			break;
		case 4:
			max = size - 3;
			int *Di = (int*)dst;
			int *Si = (int*)src;
			do{
				*(Di++) = *(Si++);
				i += 4;
			}while(i < max);
			break;
		case 2:
			max = size - 1;
			short *Ds = (short*)dst;
			short *Ss = (short*)src;
			do{
				*(Ds++) = *(Ss++);
				i += 2;
			}while(i < max);
			break;
		default:
			while(i < size){
				*(Dc++) = *(Sc++);
				i++;
			}
	}
}
con risultati


in quanto a tempi il vecchio codice è poco più veloce, ma suppone che sia un multiplo di 4 bytes... per quanto riguarda questo diciamo che la lo switch è un vero e proprio vampiro

ecco invece il codice seguendo il suggerimento di Warduck...


sembra che il cast fuori dal loop non cambi la situazione, ma forse perchè gli passo una parola da 8 bytes, adesso faccio un paio di prove con un pezzettone da 16KB
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 16:45   #9
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
E si per molta più memoria da copiare si fa sentire il cast fuori dal loop...

Ma la funzione memcpy come funziona??
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 17:26   #10
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Quote:
Originariamente inviato da clockover Guarda i messaggi
Loop unrolling... quindi è l'unico modo per ridurre al minimo i controlli e l'incremento della variabile.. In effetti ho fatto una cosa del genere (sempre per delle prove) in questo modo



e infatti il tempo perso nel controllo del while è minimo ora... ora provo altre soluzioni

edit
non sto usando nessun livello di ottimizzazione
Potresti provare a copiare i byte a 4 a 4 invece che uno alla volta (a 8 a 8 sui 64 bit).
Per semplicita': se parti da un indirizzo allineato a 4 byte e le dimensioni sono multiple di 4:

Codice:
// Nota: per semplicita', src e dst sono allineate a 4 byte; size e' multiplo di 4
void mcpy(void *src, void *dst, unsigned size) throw()
{
	register int i = size/sizeof(int);
        register int *p = (int *)src;
        register int *q = (int *)dst;
	do{
                *p++ = *q++;
	}while(--i > 0);
}

Ovviamente, se non sei allineato devi aggiungere la copia "a mano" dei primi byte e degli ultimi, fino all'allineamento.

NOTA - il predecremento, su alcuni processori (motorola in particolare) e' piu' efficiente del post decremento.
Il post decremento sugli stessi processori e' piu' efficiente del pre incremento.

Altra nota: hai parlato di C ma magari stai usando un compilatore c++. Per sicurezza potresti usare il throw() per evitare che certe implementazioni introducano un codice per la verifica di eccezioni che in realta' non possono succedere.

Altra nota ancora: sui compilatori per processori a 32 bits (quali Visual Studio), il double ha dimensione doppia (i.e. 64 bit) i quali non possono ovviamente passare tutti insieme su un bus largo la meta', ma e' probabile che si impieghi di meno a trasferire un valore 64 bit che non due botte da 32 bit. Potresti quindi provare con i puntatori double *. Ovviamente l'allineamento deve essere a 8, altrimenti il giochetto non funziona
__________________
In God we trust; all others bring data

Ultima modifica di sottovento : 10-05-2011 alle 17:31.
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 10-05-2011, 17:38   #11
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
E si infatti per ora sto facendo delle prove per rendermi conto di come alcune scelte influenzano il codice! Infatti ho creato varie versioni del codice.

Quella dell'efficienza del predecremento o del postdecremento non la sapevo.. tocca sperimentare

Intanto ho trovato questo
http://www.student.cs.uwaterloo.ca/~...8c-source.html

molto molto semplice.... ma efficiente
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 08:08   #12
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Quote:
Originariamente inviato da clockover Guarda i messaggi
E si infatti per ora sto facendo delle prove per rendermi conto di come alcune scelte influenzano il codice! Infatti ho creato varie versioni del codice.

Quella dell'efficienza del predecremento o del postdecremento non la sapevo.. tocca sperimentare

Intanto ho trovato questo
http://www.student.cs.uwaterloo.ca/~...8c-source.html

molto molto semplice.... ma efficiente
Ho guardato il link e ci sono cose che non riesco a capire, probabilmente perche' sono rimasto un po' indietro:

Codice:
     for (i=0; i<len/sizeof(long); i++) {
Il controllo di ciclo ( i < len/sizeof(long) ) deve essere effettuato ad ogni iterazione, pertanto sarebbe logico aspettarsi che rimpiazzandolo con una variabile locale:

Codice:
      int sz = len/sizeof(long);
      for (i = 0; i < sz; i++)
vi siano dei benefici. Immagino che l'abbiano pensato e se non l'hanno fatto e' perche' non hanno ottenuto dei benefici. Come mai? Lo fa il compilatore per noi?

Altra cosa: subito dopo c'e' scritto:

Codice:
d[i] = s[i];
Anche questo mi lascia perplesso. Sui vecchi processori, con i vecchi compilatori, questo risultava SICURAMENTE piu' lento di

Codice:
*d++ = *s++;
in quanto nel primo caso si doveva prendere l'indirizzo di base del vettore, calcolare lo spiazzamento in base alla dimensione del tipo ed aggiungerlo all'indirizzo di base per accedere alla locazione corretta.
Nel secondo caso si trattava di referenziare una locazione ed effettuare il post incremento. Fra l'altro, alcuni processori (es. Motorola) hanno una operazione simile nel loro set di istruzioni, quindi quest'assegnamento risultava velocissimo.

Ora non sembra piu' cosi', ma non capisco il motivo....

Infine: la memcpy() presentata all'indirizzo che hai fornito, va solo a controllare se l'allineamento e' rispettato. Se lo e', copia word a word, altrimenti byte a byte. Immagino che potrebbe essere piu' efficiente modificando il caso di non allineamento: nel caso non siano allineati, si potrebbero distinguere alcuni casi e, quando possibile, ricopiare i primi byte dopo di che procedere a word....
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 09:32   #13
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Colpa mia... questa è la memcpy di
http://www.eecs.harvard.edu/~syrah/os161/


molto sicuramente non c'entra nulla

me lo sono meritato uno schiaffettino
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 11:49   #14
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da clockover Guarda i messaggi
non sto usando nessun livello di ottimizzazione
Non ha molto senso far paragoni senza almeno un minimo di ottimizzazione.
Basta far ottimizzare l'agoritmo piu' lento presentato e andra' piu' veloce di quello "migliore" non ottimizzato.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 11:55   #15
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Penso che un buon algoritmo creato al meglio dal programmatore sarà molto efficiente anche senza ottimizzazione da parte del compilatore, figuriamoci poi ottimizzato... anche perchè il compilatore non può fare sempre dei miracoli

comunque ora sto cominciando a lavorare con livello di ottimizzazione massimo (uso GCC)

molto interessanti queste cosine... si può limare sempre qualcosina da quello che uno credeva essere un buon algoritmo (non intendo a quelli che ho postato erano solo delle prove)
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 12:29   #16
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 13043
Quote:
Originariamente inviato da clockover Guarda i messaggi
Penso che un buon algoritmo creato al meglio dal programmatore sarà molto efficiente anche senza ottimizzazione da parte del compilatore, figuriamoci poi ottimizzato... anche perchè il compilatore non può fare sempre dei miracoli

comunque ora sto cominciando a lavorare con livello di ottimizzazione massimo (uso GCC)

molto interessanti queste cosine... si può limare sempre qualcosina da quello che uno credeva essere un buon algoritmo (non intendo a quelli che ho postato erano solo delle prove)
Non ti credere, il compilatore spesso analizzando il codice può produrre ottimizzazioni che il programmatore magari neanche contemplava .

Fidati che può cambiare di molto il risultato.

Inoltre IMHO è meglio fare profiling sul programma già ottimizzato, così da individuare realmente quali siano i colli di bottiglia.
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 14:29   #17
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Quote:
Originariamente inviato da WarDuck Guarda i messaggi
Non ti credere, il compilatore spesso analizzando il codice può produrre ottimizzazioni che il programmatore magari neanche contemplava .

Fidati che può cambiare di molto il risultato.

Inoltre IMHO è meglio fare profiling sul programma già ottimizzato, così da individuare realmente quali siano i colli di bottiglia.

si più vado avanti e più mi convinco a lavorare su quello ottimizzato...

ot
forte il debugger di XCode
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 17:02   #18
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Quote:
Originariamente inviato da clockover Guarda i messaggi
sembra che il cast fuori dal loop non cambi la situazione, ma forse perchè gli passo una parola da 8 bytes, adesso faccio un paio di prove con un pezzettone da 16KB
E' perchè al 99% lo stava già spostando fuori dal ciclo il compilatore

Comunque, se l'obiettivo sono gli x86 un modo eccellente per ottimizzare le prestazioni è TOGLIERE qualsiasi operazione aritmetica e usare il loop unrolling, per trarre vantaggio dalle pipeline multiple di caricamento dalla memoria:

a[i] = b[i] è una operazione svolta interamente dalla pipeline load mentre
*a++ = *b++ deve attendere il risultato delle operazioni ++ svolte dalla pipeline aritmetica e serializza il flusso.

Anche copiare parole a 64 bit potrebbe migliorare le prestazioni su processori a 64 bits:
Codice:
void mcpy( void* src, void* dst, unsigned size )
{
     long* a = (long*)src;
     long* b = (long*)dst;
     long* end;

     size = size/sizeof( long )+1;

     end = a + size % 8;

     //resto
     while( a!= end )
          *a++ = *b++;

     end = src + size / 8;

     for( ; a != end; a += 8, b+= 8 )
     {
         //copia 64 byte per ogni ciclo
         a[0] = b[0];
         a[1] = b[1];
         a[2] = b[2];
         a[3] = b[3];
         a[4] = b[4];
         a[5] = b[5];
         a[6] = b[6];
         a[7] = b[7];
     }
}
Non so se funziona, però l'idea è quella.
__________________
*ToMmO*

devlog | twitter

Ultima modifica di Tommo : 11-05-2011 alle 17:55.
Tommo è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 17:12   #19
clockover
Senior Member
 
L'Avatar di clockover
 
Iscritto dal: Oct 2004
Messaggi: 1945
Lo vedo un po strano però quel codice non è che si alluppa al ciclo while?? E poi nel ciclo for mi copi 64 bytes non 64 bit... rischi di sforare

Comunque a parte il codice ho capito quello che intendi
clockover è offline   Rispondi citando il messaggio o parte di esso
Old 11-05-2011, 18:01   #20
Tommo
Senior Member
 
L'Avatar di Tommo
 
Iscritto dal: Feb 2006
Messaggi: 1304
Corretto, in effetti non sarebbe mai uscito dal while

I 64 byte sono voluti, per massimizzare la banda:
-ogni pipeline estrae al massimo 8 byte con una singola operazione, quindi 8 byte massimizza i byte per istruzione
-allo stesso tempo ci sono diverse pipeline che lavorano in parallelo, quindi 8 trasferimenti dovrebbe riempirle tutte.

E cmq si, il codice sfora perchè copia tutta l'ultima qword, anche se avanza solo un byte
Potrebbe creare problemi in caso di sovrascritture di roba adiacente, bisognerebbe considerare pure quello nel resto.
__________________
*ToMmO*

devlog | twitter

Ultima modifica di Tommo : 11-05-2011 alle 18:07.
Tommo è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Insta360 Luna Ultra: la potenza del sensore da 1 pollice incontra la portabilità estrema Insta360 Luna Ultra: la potenza del sensore da 1...
Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa Marvel's Wolverine, la recensione: Logan torna p...
DJI Romo 2: tante novità lo rendono un robot completo DJI Romo 2: tante novità lo rendono un ro...
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED Sony Bravia 9 II: il True RGB alla prova, dove l...
Geely EX5, un mese al volante: il SUV elettrico cinese che ci ha sorpreso (quasi) senza riserve Geely EX5, un mese al volante: il SUV elettrico ...
Googlebook pronto al debutto: Google apr...
Guida all'acquisto: quale lavapavimenti ...
Google Maps su Android Auto introduce fi...
AMD Ryzen 5 5500F: fino al 16% di presta...
L'ecosistema partner di Microsoft cresce...
Oracle registra un boom nella divisione ...
Amazon Prime Video sfida TikTok con le n...
L'uscita di Rayman Legends Retold &egrav...
Dazio UE sui pacchi extra UE, in Italia ...
La nuova lavatrice smart di Xiaomi ha tr...
Hai una PSP nel cassetto? Questo nuovo p...
Oracle presenta Java 27 con diverse novi...
Il microscopio dell'EPFL vede più...
Volvo avvia la produzione dei nuovi cami...
26 offerte Amazon da non perdere, da iPh...
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: 18:53.


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