Loop optimering - Loop optimization

I compiler teori er loopoptimering processen med at øge eksekveringshastigheden og reducere de omkostninger, der er forbundet med sløjfer . Det spiller en vigtig rolle i forbedring af cacheydelsen og effektiv anvendelse af parallelle behandlingsfunktioner . Den fleste udførelsestid for et videnskabeligt program bruges på sløjfer; som sådan er der udviklet mange kompilatoroptimeringsteknikker for at gøre dem hurtigere.

Repræsentation af beregning og transformationer

Da instruktioner inden i løkker kan udføres gentagne gange, er det ofte ikke muligt at begrænse antallet af instruktionsudførelser, der vil blive påvirket af en løkkeoptimering. Dette giver udfordringer, når man resonnerer om rigtigheden og fordelene ved en løkkeoptimering, nærmere bestemt repræsentationer for beregningen, der optimeres, og optimeringen (erne), der udføres.

Optimering via en række løbetransformationer

Loopoptimering kan ses som anvendelsen af ​​en sekvens af specifikke sløjfetransformationer (anført nedenfor eller i Compiler-transformationer til højtydende computing ) til kildekoden eller mellemrepræsentation , hvor hver transformation har en tilknyttet test for lovlighed. En transformation (eller sekvens af transformationer) skal generelt bevare den tidsmæssige sekvens af alle afhængigheder, hvis den skal bevare resultatet af programmet (dvs. være en lovlig transformation). Evaluering af fordelen ved en transformation eller sekvens af transformationer kan være ganske vanskeligt inden for denne fremgangsmåde, da anvendelsen af ​​en fordelagtig transformation kan kræve den forudgående anvendelse af en eller flere andre transformationer, der i sig selv ville resultere i reduceret ydelse.

Almindelige loop-transformationer inkluderer:

  • Fission eller distribution - sløjfe-fission forsøger at opdele en løkke i flere løkker over det samme indeksområde, men hver nye løkke tager kun en del af den oprindelige sløjpes krop. Dette kan forbedre referenceens lokalitet , både de data, der fås adgang til i løkken, og koden i loopens krop.
  • Fusion eller kombination - dette kombinerer legeme af to tilstødende sløjfer, der vil itereere det samme antal gange (uanset om dette nummer er kendt på kompileringstidspunktet eller ej), så længe de ikke henviser til hinandens data.
  • Udveksling eller permutation - disse optimeringer udveksler indre sløjfer med ydre sløjfer. Når sløjfevariabler indekseres i en matrix, kan en sådan transformation forbedre referencets lokalitet afhængigt af matrixens layout.
  • Inversion - denne teknik ændrer en standard mens løkke til en do / while (alias gentagelse / indtil  ) sløjfe indpakket i en hvis betinget, hvilket reducerer antallet af spring med to i tilfælde, hvor løkken udføres. Hvis du gør det, kopieres tilstandskontrollen (forøgelse af størrelsen på koden), men er mere effektiv, fordi hopp normalt forårsager en rørledningstal . Hvis den oprindelige tilstand er kendt på kompileringstidspunktet og er kendt for at være bivirkning- fri, kan den indledende if- guard springes over.
  • Loop-invariant kodebevægelse - dette kan i høj grad forbedre effektiviteten ved at flytte en beregning fra inde i løkken til ydersiden af ​​den, beregne en værdi lige en gang før loopen begynder, hvis den resulterende mængde af beregningen vil være den samme for hver loop-iteration ( dvs. en løkke-invariant mængde). Dette er især vigtigt med adresseberegningsudtryk genereret af sløjfer over arrays. For korrekt implementering skal denne teknik bruges med inversion, fordi det ikke er sikkert at koden flyttes uden for løkken.
  • Parallelisering - dette er et specielt tilfælde af automatisk parallelisering med fokus på sløjfer, omstrukturering af dem for at køre effektivt på multiprocessorsystemer. Det kan gøres automatisk ved hjælp af kompilatorer ( automatisk parallelisering ) eller manuelt (indsættelse af parallelle direktiver som OpenMP ).
  • Tilbageførsel - en subtil optimering, der vender rækkefølgen, i hvilken værdier er tildelt indeksvariablen. Dette kan hjælpe med at eliminere afhængigheder og således aktivere andre optimeringer. Visse arkitekturer anvender loopingkonstruktioner på samlingsniveau , der kun tæller i en enkelt retning (f.eks. Decrement-jump-if-not-zero [DJNZ]).
  • Planlægning - dette opdeler en løkke i flere dele, der kan køres samtidigt på flere processorer.
  • Skewing - denne teknik anvendes til en indlejret løkke, der itererer over en multidimensionel matrix, hvor hver iteration af den indre sløjfe afhænger af tidligere iterationer, og omorganiserer dens arrayadganger, så de eneste afhængigheder er mellem iterationer af den ydre sløjfe.
  • Softwarepipelining - en type out-of-order-eksekvering af loop-iterationer for at skjule latenser på processorfunktionsenheder.
  • Opdeling eller afskalning - dette forsøger at forenkle en løkke eller fjerne afhængigheder ved at opdele den i flere sløjfer, der har de samme organer, men gentages over forskellige dele af indeksområdet. Et specielt tilfælde er loop-peeling , som kan forenkle en loop med en problematisk første iteration ved at udføre denne iteration separat, inden den går ind i loopen.
  • Flisebelægning eller blokering - omorganiserer en løkke til at iterere over blokke af data, der er tilpasset cachen.
  • Vectorisering - forsøger at køre så mange af loop-iterationer som muligt på samme tid på et SIMD- system.
  • Unrolling - duplikerer loopens krop flere gange for at reducere antallet af gange, loop-tilstanden testes, og antallet af spring, hvilket kan forringe ydeevnen ved at forringe instruktionsrørledningen. Ved fuld udrulling af en løkke fjernes al overhead (undtagen flere instruktionshentninger og øget programbelastningstid), men kræver, at antallet af iterationer er kendt på kompileringstidspunktet (undtagen i tilfælde af Just-in-time-kompilering ). Man skal også passe på at sikre, at flere genberegninger af indekserede variabler ikke er en større omkostning end at fremme pointere inden for den oprindelige sløjfe.
  • Frakobling - flytter en betinget indvendig fra en løkke til uden for den ved at duplikere loopens krop og placere en version af den i hver af betingelserne, hvis og andet .
  • Sektionering eller strip-mining - introduceret til vektorprocessorer , loop-sectioning er en loop-transformation teknik til at aktivere SIMD (enkelt instruktion, flere data) -kodninger af sløjfer og forbedre hukommelsesydelsen. Dette involverer hver vektoroperation, der udføres for en størrelse, der er mindre end eller lig med den maksimale vektorlængde på en given vektormaskine.

Den unimodular transformation ramme

Den unimodulære transformationsmetode bruger en enkelt unimodulær matrix til at beskrive det kombinerede resultat af en sekvens af mange af de ovennævnte transformationer. Centralt i denne tilgang er synspunktet om sættet af alle henrettelser af en erklæring inden for n sløjfer som et sæt heltalspunkter i et n- dimensionelt rum, hvor punkterne udføres i leksikografisk rækkefølge . F.eks. Kan henrettelserne af en sætning, der er indlejret inde i en ydre sløjfe med indeks i og en indre sløjfe med indeks j, være forbundet med parret med heltal . Anvendelsen af ​​en unimodular transformation svarer til multiplikationen af ​​punkterne inden for dette rum med matrixen. For eksempel svarer udvekslingen af ​​to sløjfer til matrixen .

En unimodular transformation er lovlig, hvis den bevarer den tidsmæssige rækkefølge af alle afhængigheder ; Det er vanskeligere at måle ydeevneeffekten af ​​en unimodular transformation. Ufuldkomne indlejrede sløjfer og nogle transformationer (såsom flisebelægning) passer ikke let ind i denne ramme.

Den polyhedrale eller begrænsningsbaserede ramme

Den polyhedrale model håndterer en bredere klasse af programmer og transformationer end den unimodulære ramme. Sættet med henrettelser af et sæt udsagn inden for et muligvis ufuldstændigt indlejret sæt løkker ses som foreningen af ​​et sæt polytoper, der repræsenterer henrettelsernes henrettelser. Affinetransformationer anvendes til disse polytoper, hvilket giver en beskrivelse af en ny eksekveringsordre. Grænserne for polytoper, datafhængigheder og transformationer beskrives ofte ved hjælp af systemer med begrænsninger, og denne fremgangsmåde omtales ofte som en begrænsningsbaseret tilgang til loopoptimering. For eksempel udføres en enkelt sætning i en ydre sløjfe ' for i: = 0 til n ' og en indre sløjfe ' for j: = 0 til i + 2 ' en gang for hvert (i, j) par, således at 0 <= i <= n og 0 <= j <= i + 2 .

Endnu en gang er en transformation lovlig, hvis den bevarer den tidsmæssige rækkefølge af alle afhængigheder . At estimere fordelene ved en transformation eller finde den bedste transformation for en given kode på en given computer forbliver genstand for løbende forskning fra tidspunktet for denne skrivning (2010).

Se også

Referencer