ottimizzazione Loop - Loop optimization
In teoria compilatore , ottimizzazione del ciclo è il processo di aumentare la velocità di esecuzione e riducendo le spese associate con anse . Essa svolge un ruolo importante nel miglioramento della cache delle prestazioni e utilizzare efficacemente elaborazione parallela capacità. La maggior tempo di esecuzione di un programma scientifico viene speso per cicli; come tale, molti di ottimizzazione compilatore tecniche sono state sviluppate per renderli più veloci.
Contenuto
Rappresentazione di calcolo e trasformazioni
Dal momento che le istruzioni all'interno di cicli possono essere eseguiti più volte, non è spesso possibile dare un limite al numero di esecuzioni di istruzioni che sarà influenzato da un'ottimizzazione del ciclo. Questo presenta sfide quando ragionamento sulla correttezza e benefici di un'ottimizzazione ciclo, in particolare le rappresentazioni del calcolo ottimizzati e l'ottimizzazione (s) essendo eseguite.
L'ottimizzazione tramite una sequenza di trasformazioni di loop
Ottimizzazione loop può essere considerata l'applicazione di una sequenza di specifici trasformazioni anello (elencati di seguito o in trasformazioni compilatore di calcolo ad alte prestazioni ) al codice sorgente o rappresentazione intermedia , con ogni trasformazione avente un test associato per la legalità. Una trasformazione (o una sequenza di trasformazioni) generalmente deve mantenere la sequenza temporale di tutte le dipendenze se è preservare il risultato del programma (ad esempio, essere una trasformazione legale). Valutare il beneficio di una trasformazione o una sequenza di trasformazioni può essere molto difficile in questo approccio, come l'applicazione di una benefica trasformazione può richiedere l'uso precedente di una o più altre trasformazioni che, da soli, comporterebbe prestazioni ridotte.
trasformazioni del ciclo comuni includono:
- Fissione o distribuzione - ciclo fissione tenta di rompere un loop in cicli multipli nello stesso intervallo di indice, ma ogni nuovo ciclo richiede solo una parte del corpo del loop originale. Ciò può migliorare frazione di riferimento , sia dei dati a cui si accede nel ciclo e il codice nel corpo del ciclo.
- Fusione o combinando - questo unisce i corpi di due spire adiacenti che iterare lo stesso numero di volte (se tale numero è noto al momento della compilazione), purché non fanno riferimento a dati reciproche.
- Interchange o permutazione - queste ottimizzazioni scambiano cicli interni con i loop esterni. Quando l'indice variabili del loop in una matrice, una tale trasformazione può migliorare frazione di riferimento, in funzione della configurazione della matrice.
- Inversione - questa tecnica cambia uno standard mentre ciclo in una do / while (alias ripetere / fino ) anello avvolto in un caso condizionale, riducendo il numero di salti da due per i casi in cui il ciclo viene eseguito. In questo modo duplica il controllo di condizione (l'aumento delle dimensioni del codice), ma è più efficiente perché i salti di solito causano una stalla gasdotto . Inoltre, se la condizione iniziale è noto al momento della compilazione e si caratterizza per essere effetto collaterale -free, l'iniziale se -guard possono essere saltati.
- Loop-invariante codice motion - questo può migliorare notevolmente l'efficienza spostando un calcolo dall'interno del ciclo di fuori di esso, calcolando un valore solo una volta prima del ciclo ha inizio, se la quantità risultante del calcolo sarà la stessa per ogni iterazione del ciclo ( Per esempio, una quantità loop-invariante). Ciò è particolarmente importante con le espressioni indirizzo-calcolo generati dai loop oltre array. Per una corretta attuazione, questa tecnica deve essere usata con inversione, perché non tutto il codice è sicuro di essere spostato all'esterno del ciclo.
- Parallelizzazione - questo è un caso particolare di parallelizzazione automatica concentrandosi sui cicli, loro ristrutturazione per funzionare in modo efficiente su sistemi multiprocessore. Può essere fatto automaticamente dai compilatori ( parallelizzazione automatica ) o manualmente (inserendo direttive parallele come OpenMP ).
- Inversione - un'ottimizzazione sottile che inverte l'ordine in cui vengono assegnati i valori per la variabile indice. Questo può aiutare a eliminare le dipendenze e, quindi, abilitare altre ottimizzazioni. Alcune architetture utilizzano costrutti di ciclo a montaggio livello che contano in un unico senso unico (ad esempio, decremento-salto-se-non zero [DJNZ]).
- Scheduling - questo divide un anello in più parti che possono essere eseguiti contemporaneamente su più processori.
- Inclinazione - questa tecnica viene applicata ad un'iterazione ciclo annidato su una matrice multidimensionale, dove ogni iterazione del ciclo interno dipende iterazioni precedenti, e cambia la sua matrice accede modo che le sole dipendenze tra iterazioni del ciclo esterno.
- Software pipelining - un tipo di esecuzione fuori ordine di iterazioni per nascondere le latenze di unità funzionali processore.
- Scissione o peeling - questo tentativo di semplificare un loop o eliminare le dipendenze rompendo in cicli multipli che hanno gli stessi corpi ma iterano su diverse porzioni del campo di indice. Un caso particolare è ciclo peeling , che può semplificare un ciclo con una problematica prima iterazione eseguendo che iterazione separatamente prima di entrare nel ciclo.
- Rivestimenti o il blocco - riorganizza un ciclo per iterare su blocchi di dati di dimensioni per adattarsi nella cache.
- Vettorializzazione - tenta di eseguire il maggior numero di iterazioni del ciclo il più possibile allo stesso tempo su un SIMD sistema.
- Srotolando - duplica il corpo del ciclo più volte, al fine di diminuire il numero di volte che la condizione del ciclo viene testato e il numero di salti, che possono degradare le prestazioni ostacolando lo pipeline. Completamente srotolando un ciclo elimina tutte le spese generali (ad eccezione di istruzioni multiple recupera e maggiore tempo di caricamento del programma), ma richiede che il numero di iterazioni essere noto al momento della compilazione (tranne che nel caso di compilazione just-in-time ). Si deve anche prestare attenzione a garantire che più ricalcolo delle variabili indicizzati non è un overhead maggiore di avanzare puntatori all'interno del loop originale.
- Unswitching - muove un condizionale all'interno di un ciclo di fuori di esso duplicando il corpo del ciclo, e mettendo una versione di esso all'interno di ciascuno dei se e altro clausole del condizionale.
- Sezionamento o strip-mining - introdotta per processori vettoriali , loop-sezionamento è una tecnica loop-trasformazione per abilitare SIMD (Single Instruction, più dati) -codici di loop e migliorando le prestazioni della memoria. Ciò comporta ogni operazione vettore viene fatto per una dimensione minore di o uguale alla massima lunghezza del vettore su una determinata macchina vettore.
Il quadro trasformazione unimodulare
L'approccio trasformazione unimodulare utilizza una singola matrice unimodulare per descrivere il risultato combinato di una sequenza di molte delle trasformazioni sopra. Al centro di questo approccio è la vista dell'insieme di tutte le esecuzioni di un'istruzione all'interno n cicli come un insieme di punti interi in n spazio dimensionale, con i punti che sono eseguiti in ordine lessicografico . Ad esempio, le esecuzioni di un'istruzione annidato in un anello esterno con indice i e un ciclo interno con indice j possono essere associati alle coppie di interi . L'applicazione di una trasformazione unimodulare corrisponde alla moltiplicazione dei punti all'interno di questo spazio dalla matrice. Ad esempio, lo scambio di due cicli corrisponde alla matrice .
Una trasformazione unimodulare è legale se conserva la sequenza temporale di tutte le dipendenze ; misurare l'impatto sulle prestazioni di una trasformazione unimodulare è più difficile. Imperfettamente cicli annidati e alcune trasformazioni (come ad esempio piastrelle) non si adattano facilmente in questo quadro.
Il quadro poliedrica o vincolo-based
Il modello di poliedrica gestisce una classe più ampia di programmi e delle trasformazioni che il quadro unimodulare. L'insieme di esecuzioni di un insieme di istruzioni all'interno di un insieme eventualmente imperfettamente nested di loop è visto come l'unione di un insieme di politopi rappresentano le esecuzioni delle istruzioni. Trasformazioni affini vengono applicate a tali politopi, producendo una descrizione di un nuovo ordine di esecuzione. I confini dei politopi, le dipendenze di dati, e le trasformazioni sono spesso descritti utilizzando sistemi di vincoli, e questo approccio è spesso definito come un vincolo a base di approccio alla ottimizzazione del ciclo. Ad esempio, una singola istruzione all'interno di un ciclo esterno ' per i: = 0 a n ' e un ciclo interno ' per j: = 0 per i + 2 ' viene eseguito una volta per ogni (i, j) coppia tale che 0 <= i <= n e 0 <= j <= i + 2 .
Ancora una volta, una trasformazione è legale se conserva la sequenza temporale di tutte le dipendenze . La stima dei benefici di una trasformazione, o di trovare il miglior trasformazione per un determinato codice su un determinato computer, rimane oggetto di ricerca in corso a partire dal momento in cui scriviamo (2010).