• Non ci sono risultati.

La maggior parte dei microcontrollori e dei DSP sono messi in commercio con il supporto di compilatori e simulatori. Tuttavia nel caso dei DSP in virgola fissa è noto che la qualità dei codici generati dai compilatori è spesso insufficiente; in molti casi questi ultimi sono basati su un software standard di compilazione sviluppato tra gli anni ’70 e ’80 e non sono adattati alla particolare architettura del DSP. Tutto ciò implica che nei nostri giorni i team di design sono costretti a spendere una rilevante quantità di tempo per scrivere in linguaggio macchina (di solito in assembler) le loro applicazioni. Questa situazione porta a degli ovvi inconvenienti, tra i quali è da sottolineare l’aumento dei costi e dei tempi legati allo sviluppo. Inoltre il codice così ottenuto difficilmente si può trasferire ad un nuovo processore, cosa che risulta altamente indesiderabile in un’era in cui il tempo di vita di un processore è molto basso e l’innovazione architetturale è una chiave del successo di un prodotto.

Fortunatamente la comunità di ricerca sta rispondendo a questi inconvenienti con un rinnovato interesse nello sviluppo di software per la compilazione per sistemi embedded [31].

Gli obiettivi che ci si propone di raggiungere riguardano soprattutto due aspetti: 1. Adattabilità alle architetture: gli strumenti per la compilazione dovrebbero

essere adattabili il più possibile alle diverse architetture dei processori. Si tratta di un fattore essenziale, in quanto come si è visto, le architetture dei DSP e degli ASIP sono soggette a frequenti variazioni e quindi è necessaria un’alta adattabilità per supportare i designer con strumenti validi per la compilazione.

2. Qualità nel codice: le istruzioni e il numero di cicli del codice macchina compilato dovrebbero essere confrontabili con le soluzioni ottenute manualmente da programmatori esperti di assembler:

• Un’alta velocità di esecuzione è essenziale per sopperire ai vincoli imposti dal sistema embedded in real-time.

• Un’alta densità di codice macchina è richiesta se il programma deve risiedere sul chip e in questo caso si ottiene anche il risultato di avere una minore dissipazione di potenza e di occupare una minore area di silicio.

La maggior parte dei produttori offrono i loro processori già corredati di compilatori per linguaggio C. Si tratta di versioni adattate del GCC, che è un modello di compilatore distribuito dalla Free Software Foundation [32].

Sebbene la comunità abbia adattato i sorgenti del GCC, distribuiti liberamente, alle più comuni architetture come ad esempio quella dell’ADSP-21xx, il codice generato dai compilatori disponibili per DSP in virgola fissa è spesso inaccettabile per scopi industriali, così i team di sviluppo devono ricorrere all’assembler. Tuttavia la comunità scientifica si sta muovendo verso un miglioramento dei compilatori introducendo diverse tecniche in grado di ottimizzare sempre più il codice macchina generato.

Questo lavoro di tesi è stato sviluppato inizialmente sotto l’ambiente Matlab, in seguito si è voluto implementarne il software in un sistema embedded portatile basato su un processore della famiglia ADSP-21xx (vedi paragrafo 1.4). In quella fase si è presentata la necessità di convertire il codice Matlab nel C/C++ del compilatore fornito con il DSP. Operando questa conversione si è andati incontro alla necessità di ottimizzare il sistema per rispondere ai vincoli imposti dal real- time nonché dalla bassa disponibilità di memoria.

Le modifiche apportate al codice di partenza sono elencate qui di seguito:

1. Eliminazione della memoria dinamica: la memoria disponibile nel sistema embedded è predefinita e quindi è stato necessario sovradimensionare tutte le variabili presenti nel programma in modo da avere chiara l’occupazione di memoria e non incorrere in errori di allocazione.

2. Velocizzazione delle operazioni: l’eliminazione della memoria dinamica in parte contribuisce a questo secondo punto, in quanto il sistema non perde tempo nell’allocazione della memoria; inoltre, molte funzioni del programma sono state ottimizzate modificando alcuni cicli ed eliminando alcune istruzioni condizionate, rese ormai inutili dal sovradimensionamento delle variabili. In tal modo si è ottenuta una

maggiore velocità di esecuzione del programma con evidente beneficio per il funzionamento in real-time.

L’esempio successivo, estratto dai sorgenti modificati della libreria LIBSVM, citata nel paragrafo 3.6, mostra come si è proceduto per ottenere l’eliminazione della memoria dinamica:

// originale

double Kernel::dot(const svm_node *px, const svm_node *py) {

double sum = 0;

while(px->index != -1 && py->index != -1) {

if(px->index == py->index) {

sum += px->value * py->value; ++px; ++py; } else { if(px->index > py->index) ++py; else ++px; } } return sum; }

Da questo spezzone di codice originale si nota l’uso della memoria dinamica. Il codice modificato invece risulta:

// ************* nuova implementazione con array *********** double Kernel::dot(const double *px, const double *py)

{

int i;

double sum = 0;

for (i=0; i<ARRAY_DIM; i++) sum += px[i]*py[i];

return sum;

}

Si vede chiaramente che tutta la funzione è stata ottimizzata e procede molto più velocemente, in quanto i puntatori sono stati tutti sostituiti con array di dimensioni predefinite ARRAY_DIM.

3. Conversione delle variabili da 32 a 16 bit: la scelta si è resa necessaria a causa della bassa disponibilità di memoria, tuttavia le prestazioni generali del sistema non hanno risentito più di tanto di questo cambiamento nonostante l’inevitabile approssimazione effettuata sui valori numerici. 4. Eliminazione della memorizzazione su file: i programmi enunciati nel

paragrafo 3.6 e presenti nella libreria utilizzano, per il funzionamento, file di testo contenenti tanto le features da riconoscere quanto tutti i parametri ottenuti nel processo di training, in quanto in un sistema embedded non c’è possibilità di memorizzazione su disco; solo i parametri ottenuti dopo il train vengono salvati nella flash per essere utilizzati ogni qualvolta se ne presenti la necessità, dal momento che il programma è concepito per funzionare in real-time senza ricorrere a memorizzazioni permanenti. Oltre queste modifiche indicate ai punti 1,2,3,4, nel corso del lavoro si è profilata via via l’opportunità di operare altre scelte, che si troveranno elencate alla fine del prossimo capitolo.

Cap. V

Risultati sperimentali

Questo capitolo racchiude una trattazione sugli esperimenti effettuati per arrivare alla progettazione ottimale del sistema per riconoscimento. Il capitolo è suddiviso in sezioni che trattano specificamente le prove effettuate.

Documenti correlati