Sei sulla pagina 1di 23

Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 22

Scrivere codice (in un linguaggio di alto livello) veloce

I linguaggi di alto livello vengono prima compilati in un byte-code


indipendente dallhardware che poi viene interpretato.

Viceversa linguaggi come il C, Fortran traducono il codice in istruzioni


macchina fortemente dipendenti dallhardware.

Questo fatto penalizza quasi sempre le prestazioni dei linguaggi di alto


livello sebbene in qualche caso si possano avere risultati addirittura
migliori (ad esempio nella processazione di testi).

In ogni caso sempre possibile utilizzare delle tecniche ad-hoc che


consentano di migliorare lefficienza dei codici mantenendone per la
flessibilit, semplicit etc.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 23

Scrivere codice MATLAB veloce 1

MATLAB offre numerose possibilit per velocizzare i suoi codici:


preallocazione
ottimizzazione JIT
vettorizzazione
...
Queste tecniche sono quasi sempre di aiuto ma la loro efficacia va valutata
caso per caso. Alcune controindicazioni:
non conviene ottimizzare una parte se questa pesa molto poco
allinterno dellapplicazione
un codice estremamente ottimizzato pu risultare molto meno
comprensibile delloriginale.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 24

Scrivere codice MATLAB veloce 2

Vediamo un semplice esempio che mostra come gran parte delle


ottimizzazioni da utilizzare in un contesto di codice compilato rimangono
vere.
Supponiamo di avere una matrice A m n e un vettore x n 1. Vogliamo
formare il vettore y=Ax. In MATLAB scriveremmo semplicemente:
>> y=A*x;
Vediamo due algoritmi alternativi. Il primo utilizza il concetto di prodotto
scalare tra le righe della matrice A e il vettore x:

yi = A(i, :) x (i = 1, ..., m)

Il secondo invece utilizza le colonne della matrice A in questo modo:

A x = x(1) A(:, 1) + x(2) A(:, 2) + ... + x(n) A(:, n)

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 25

Scrivere codice MATLAB veloce 3

Sorprendentemente, bench i due algoritmi hanno lo stesso numero di


operazioni, lelapsedtime notevolmente diverso.
Scriviamo emandiamo in esecuzione lo script cachetest.m:
c l e a r ; n =2048;
A= r a n d ( n ) ;
x= r a n d ( n , 1 ) ;
y= z e r o s ( n , 1 ) ;
d i s p ( primo test ) ;
t i c ; f o r i = 1 : n , y ( i ) =A( i , : ) x ; , end ; t o c
d i s p ( secondo test ) ;
t i c ; f o r i = 1 : n , y=y+x ( i ) A ( : , i ) ; end ; t o c
d i s p ( A*x ) ;
t i c ; y=A x ; t o c

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 26

Scrivere codice MATLAB veloce 4

>> cachetest
primo test
Elapsed time is 0.203873 seconds.
secondo test
Elapsed time is 0.023361 seconds.
A*x
Elapsed time is 0.010208 seconds.
>>
Il secondo algoritmo notevolmente pi veloce del primo e
confrontabile con la funzione builtin.
La differenza di velocit si spiega con il fatto che MATLAB memorizza
la matrice per colonne e quindi il primo algoritmo soffre di problemi di
Memory Management (cache, etc).

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 27

Il Profiler 1

Questo tool aiuta a determinare i bottlenecks nel codice. Vediamo un


semplice esempio:
f u n c t i o n e x a m p l e 1 ( Count )
f o r k = 1 : Count
result (k) = sin (k /50) ;
i f r e s u l t ( k ) < 0.9
r e s u l t ( k ) = gammaln ( k ) ;
end
end

Possiamo mandare in esecuzione la funzione dando il parametro di input


(Count):

>> example1(5000);

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 28

Il Profiler 2

Per analizzare lefficienza della funzione abilitiamo il Profiler:


>> profile clear
>> profile on
>> tic;example1(20000);toc
Elapsed time is 1.204688 seconds.
>> profreport(example1)
Il Profiler genera un file HTML e lancia una finestra di report della frazione
di tempo di esecuzione speso da ciascuna funzione.
Si pu andare maggiormente in dettaglio istanziando la funzione con un
semplice mouseclick.
Il risultato che il codice spende la maggior parte del tempo nella chiamata
della funzione trigonometrica sin:

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 29

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 30

Preallocazione 1

Una delle caratteristiche principali di MATLAB la cosiddetta allocazione


della memoria dinamica. Un esempio:
>> a=2
a =
2
>> a(2,6)=1
a =

2 0 0 0 0 0
0 0 0 0 0 1
Internamente la memoria allocata dalla matrice deve essere riallocata. Se
questoperazione avviene allinterno di un ciclo la velocit di esecuzione
pu risentirne.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 31

Preallocazione 2

Per evitare questo problema buona norma preallocare la memoria richiesta


dalla matrice al suo valore massimo. Vediamolo con un semplice esempio:
a ( 1 ) =1;
b ( 1 ) =0;
f o r k =2:20000
a ( k ) = 0 . 9 9 8 0 3 a ( k 1) 0.06279 b ( k 1) ;
b ( k ) = 0 . 0 6 2 7 9 a ( k 1) + 0 . 9 9 8 0 3 b ( k 1) ;
end

Mandandolo in esecuzione:

>> tic;example;toc
Elapsed time is 2.475201 seconds.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 32

Preallocazione 3

Cambiamo lo script utilizzando la funzione zeros di MATLAB ed


otteniamo un notevole speedup nelle prestazioni:
a= z e r o s ( 1 , 2 0 0 0 0 ) ;
b= z e r o s ( 1 , 2 0 0 0 0 ) ;
a ( 1 ) =1;
b ( 1 ) =0;
f o r k =2:20000
a ( k ) = 0 . 9 9 8 0 3 a ( k 1) 0.06279 b ( k 1) ;
b ( k ) = 0 . 0 6 2 7 9 a ( k 1) + 0 . 9 9 8 0 3 b ( k 1) ;
end

>> tic;example;toc
Elapsed time is 0.006386 seconds.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 33

Ottimizzazione JIT

MATLAB un linguaggio di alto livello pertanto uno script MATLAB


viene processato in due parti:
Il codice MATLAB viene convertito in linguaggio intermedio detto
pcode
Linterprete esegue ogni istruzione del pcode in sequenza.
Come risultato un certo overhead associato allesecuzione di una
istruzione del pcode. A seconda dellistruzione pu accadere che l
overhead sia confrontabile col suo tempo di esecuzione: le prestazioni
saranno pertanto pessime!
Un altro problema che linterprete deve gestire il caso pi generale e
complicato possibile. Questo fatto genera ulteriore overhead specialmente
nel caso di operazioni su valori scalari.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 34

Ottimizzazione JIT 2

Lottimizzazione JIT (Just In Time una funzionalit builtin di MATLAB


che consente di velocizzare codice MATLAB riducendo loverhead di
alcune istruzioni. Si compone di:

Just In Time Code Generation in cui istruzioni pcode vengono


convertite in linguaggio macchina. Loverhead risulta
drammaticamente ridotto.

Runtime Type Analysis che si basa sul fatto (quasi sempre vero) che
se una linea di codice stata processata, tutte le variabili manterranno
stessi tipi e dimensioni in successive chiamate. Viene pertanto generato
codice adhoc che pu essere utilizzato in seguito.
Se tipo o dimensione della variabile cambia, il codice sar rigenerato.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 35

Ottimizzazione JIT 3

Trarranno vantaggio da questo tipo di ottimizzazione codici che fanno


grande uso di valori scalari o cicli for. In generale codici che non
possibile vettorizzare in modo immediato. Vediamo un semplice esempio:
a = 2.5; b = 3.33; c = 6.23;
f o r i = 1:1000000
a = b + c;
b = a c;
c = b a;
if (a > b)
a = b c;
else
b = b + 12.3;
end , end

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 36

Ottimizzazione JIT 4

Mandando in esecuzione lo script lelapsedtime risibile. Il codice stato


accelerato:

>> tic;simple;toc
Elapsed time is 0.169312 seconds.

Questo tipo di ottimizzazione presenta per il problema di dipendere


fortemente dal fatto che le istruzioni allinterno del ciclo for siano
operazioni matematiche o al pi builtin.
Anche una semplice chiamata ad una funzione utente pu annullare
lottimizzazione perch linterprete non conosce in anticipo il tipo o
dimensione del dato utilizzato nel nuovo script.
Cambiamo lo script simple.m introducendo solamente la funzione intdummy
che assegna il valore corretto allindice del ciclo for.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 37

Ottimizzazione JIT 5

a = 2.5; b = 3.33; c = 6.23;


f o r i = 1 : intdummy
a = b + c;
b = a c;
c = b a;
if (a > b)
a = b c;
else
b = b + 12.3;
end , end

dove:
f u n c t i o n d=intdummy
d =1000000;

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 38

Ottimizzazione JIT 6

Il risultato un codice circa 20 volte pi lento delloriginale:

>> tic;simplebad;toc
Elapsed time is 2.470977 seconds.

Altre limitazioni:

Matrici sparse o array 3-D (o pi).

Overloading di operatori matematici di default.

Espressioni condizionali if, elseif, while, switch che non valutino uno
scalare.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 39

Vettorizzazione 1

Si dice che un calcolo vettorizzato quando si eseguono delle


operazioni sullintero array piuttosto che elemento per elemento.

La vettorizzazione sfrutta appieno le potenzialit di MATLAB poich


molte funzioni MATLAB sono gi vettorizzate:
>> A=rand(100);
>> B=sqrt(A);

In generale, si richiede la conoscenza delle funzioni builtin gi


vettorizzate e una buona comprensione del tipo di calcolo che si vuole
svolgere.

Non esistono regole generali, va studiato caso per caso.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 40

Vettorizzazione 2

Consideriamo la funzione minDistance:


function d = minDistance ( x , y , z )
nPoints = length (x) ;
d = zeros ( nPoints , 1 ) ;
f o r k =1: n P o i n t s
d ( k ) = s q r t ( x ( k ) ^2+ y ( k ) ^2+ z ( k ) ^ 2 ) ;
end
d=min ( d ) ;

La funzione builtin length calcola la lunghezza del vettore. Un esempio di


utilizzo il seguente:

>> x=rand(10000000,1); y=rand(10000000,1); z=rand(10000000,1);


>> tic;d=minDistance(x,y,z);toc
Elapsed time is 2.397184 seconds

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 41

Vettorizzazione 3

Per vettorizzare questa funzione dobbiamo semplicemente rimpiazzare il for


loop con unoperazione vettoriale. Il nuovo codice :
function d = minDistance1 ( x , y , z )
d = s q r t ( x .^2+ y .^2+ z . ^ 2 ) ;
d=min ( d ) ;

Si noti loperatore che agisce sullintero vettore nel calcolo della


funzione distanza. Il nuovo codice pi veloce:
>> x=rand(10000000,1); y=rand(10000000,1); z=rand(10000000,1);
>> tic;d=minDistance1(x,y,z);toc
Elapsed time is 0.45808 seconds
e dobbiamo attenderci vantaggi anche maggiori al crescere della
dimensione dei dati.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 42

Logica Vettorizzata

Spesso un calcolo realistico composto, oltre che da una parte


computazionale, da una parte dove sono utilizzate operazioni condizionali
(logica). Anche questo tipo di operazioni vettorizzato in MATLAB
mediante luso di funzioni specializzate come il find.
Ad esempio listruzione complessa:

>> i=find(isnan(x) |isinf(x));x(i)=[];

rimuove dal dataset x i valori NaN ed Inf.


Il codice risulta estremamente ottimizzato nonch compatto. Sarebbe
difficile ottenere entrambi gli obiettivi anche con un linguaggio come il C.

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 43

Attenzione alla Vettorizzazione 1

Questo semplice esempio assegna ad un vettore y la somma dei primi j


elementi di un altro vettore x, ossia:

y j = x1 + x2 + ... + x j

Mandiamo in esecuzione lalgoritmo non vettorizzato:


>> clear; n=2000; x = 1:n; x = x(:); y = zeros(n,1);
>> t=cputime; for j=1:n, for k=1:j, y(j)=y(j)+x(k); end,end,cputime-t
ans = 2.8700
Chiaramente possiamo vettorizzare almeno parzialmente utilizzando la
funzione builtin sum, ossia:
>> t=cputime; for j=1:n, y(j)=sum(x(1:j)); end, cputime-t
ans = 0.0300

Scuola Estiva di Calcolo Avanzato 2008


Piero Lanucara, Fabio Bonaccorso MATLAB Avanzato: 44

Attenzione alla Vettorizzazione 2

Chiaramente le cose sono molto migliorate ma, sorprendentemente (?):


>> t=cputime; y = tril(ones(n))*x; cputime-t
ans = 0.1100
le cose peggiorano vettorizzando completamente il codice utilizzando le
funzioni builtin tril e ones. Infatti:
>> A=tril(ones(4))
A =
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
e di conseguenza vi un certo numero di moltiplicazioni per 0 in A*x.

Scuola Estiva di Calcolo Avanzato 2008

Potrebbero piacerti anche