vorlesung, wintersemester 2009/10m. schölzel 1 optimierungstechniken in modernen compilern...

24
orlesung, Wintersemester 2009/10 M. Schölzel Optimierungstechniken in modernen Compilern Einführung

Upload: fritzi-gerst

Post on 05-Apr-2015

115 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

1

Vorlesung, Wintersemester 2009/10 M. Schölzel

Optimierungstechniken in modernen Compilern

Einführung

Page 2: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

2Optimierungstechniken in modernen Compilern Einführung

Klassifizierung von Computersystemen

Klassifizierung nach Flynn:

Single Instruction Single Data (SISD): Ein einzelner Prozessor führt einen Befehlsstrom auf Daten in einem

Datenspeicher aus.

Multiple Instruction Single Data (MISD): Eine Sequenz von Daten aus

demselben Speicher wird von mehreren Ausführungseinheiten bearbeitet, von denen jede einen

eigenen Steuerfluss besitzt.

Single Instruction Multiple Data (SIMD): Ein einzelner Befehl steuert mehrere Ausführungseinheiten, von denen jede Zugriff auf einen lokalen

Speicher hat.

Multiple Instruction Multiple Data (MIMD): Mehrere Steuerflüsse

steuern mehrere Ausführungseinheiten, von denen jede

Zugriff auf einen lokalen Speicher hat.

Es

exis

tier

t ei

n

Ste

uer

flu

ss i

m

Pro

gra

mm

.

Es

exis

tier

en

meh

rere

S

teu

erfl

üss

e im

P

rog

ram

m.

Alle Ausführungseinheiten greifen auf denselben

Datenspeicher zu.

Jede Ausführungseinheiten besitzt einen lokalen

Datenspeicher (z.B. einen Cache).

Page 3: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

3Optimierungstechniken in modernen Compilern Einführung

Einordnung von Prozessorarchitekturen

Prozessororganisation

SISD SIMD MISD MIMD

Shared Memory

Distributed Memory

ClusterSymmetric Multiprocessor

(SMP)

Non-UniformMemory Access

(NUMA)

Vector Processor

Array Processor

Uniprocessor

Scalar Superscalar

Dynamic Scheduled

Static Scheduled

Static AllocationDynamic Allocation

i386, i486

Pentium

VLIW: Transmeta Crusoe, Philips

TriMedia

GeclusterteVLIWs

Dual-Core Pentium

Itanium

TMS320C62x

Page 4: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

4Optimierungstechniken in modernen Compilern Einführung

Skalarer Prozessor ohne Pipeline

Typische Optimierungen des Compilers: Registerdruck minimieren Geeigneten Zielcode auswählen

Ste

ue

rwe

rk

Registerbank

ALU

Speicher

ldm (r8) r0

ldm (r9) r1

ldm (r10) r2

add r0,r1 r0

add r0,r2 r0

use r8,r9,r10

ldm (r8) r0

ldm (r9) r1

add r0,r1 r0

ldm (r10) r1

add r0,r1 r0

use r8,r9,r10

ldc #8 r0

add r0,r8 r0

ldm (r0) r1

ldm (r8+8) r1

Speicher

Speicher

Schematischer Aufbau:Hoher Registerdruck: Geringer Registerdruck:

Schlechte Codeauswahl: Bessere Codeauswahl:

Page 5: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

5Optimierungstechniken in modernen Compilern Einführung

Skalarer Prozessor mit Befehlspipeline

Typische Optimierungen des Compilers: Registerdruck minimieren Geeigneten Zielcode auswählen Pipeline-Hazards vermeiden

Registerbank

ALU

Speicher

FE/DE

Speicher

DE/EX

EX/MEM

Ste

ue

rwe

rk

MMU

MEM/WB

ldm (r8) r0

ldm (r9) r1

stall

stall

add r0,r1 r0

ldm (r10) r2

stall

stall

add r0,r2 r0

ldm (r8) r0

ldm (r9) r1

ldm (r10) r2

stall

add r0,r1 r0

stall

stall

add r0,r1 r0

Schematischer Aufbau:Schlechte Befehlsanordnung:

Bessere Befehlsanordnung:

Page 6: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

6Optimierungstechniken in modernen Compilern Einführung

Superskalarer Prozessor

Typische Optimierungen des Compilers: Registerdruck minimieren Geeigneten Zielcode auswählen Umordnung der Operationen, um Abhängigkeiten zwischen Operationen im Befehlspuffer

zu minimieren.

Registerbank

ALU Speicher

DE1/DE2

DE2/EX

EX/MEM

Ste

ue

rwe

rk

MMUALU

FE/DE1

Speicher

Befehlspuffer

add r0,r1 r2

add r0,r2 r2

add r0,r3 r4

add r0,r4 r4

add r0,r1 r2

add r0,r3 r4

add r0,r2 r2

add r0,r4 r4

Schlechte Befehls-anordnung für Puffer mit Kapazität 2:

Schematischer Aufbau:

Bessere Befehls-anordnung für Puffer mit Kapazität 2:

Page 7: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

7Optimierungstechniken in modernen Compilern Einführung

VLIW

Typische Optimierungen des Compilers: Registerdruck minimieren Geeigneten Zielcode auswählen Pipeline-Hazards vermeiden Feingranulare Parallelität erkennen und Operationen statisch

parallelisieren.

Registerbank

ALU Speicher

FE/DE

DE/EX

EX/MEM

Ste

ue

rwe

rk

MMUALU

Speicheradd r0,r1 r2

add r0,r2 r2

add r0,r3 r4

add r0,r4 r4

add r0,r1 r2 | add r0,r3 r4

add r0,r2 r2 | add r0,r4 r4

Schematischer Aufbau: Sequentieller Programmcode:

Parallelisierter Programmcode:

Page 8: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

8Optimierungstechniken in modernen Compilern Einführung

SMP

Typische Optimierungen: Grobgranulare Parallelität erkennen und das Programm in Threads aufteilen,

so dass wenig Synchronisation zwischen den Threads erforderlich ist. Registerdruck minimieren Geeigneten Zielcode auswählen Pipeline-Hazards vermeiden

call f

call gcall f

Registerbank

ALU

FE/DESpeicher

DE/EX

EX/MEM

Steu

erw

erk

MMU

MEM/WB

Registerbank

ALU

FE/DESpeicher

DE/EX

EX/MEM

Steu

erw

erk

MMU

MEM/WB

Bus

ldc #100 r0

loopHead:

dec r0

cmp r0,#0

jnz loopHead

ldc 100 r0

loopHead:

dec r0

cmp r0,#50

jg loopHead

ldc 50 r0

loopHead:

dec r0

cmp r0,#0

jnz r0 loopHead

Cache Cache

gemeinsamer Speicher

Schematischer Aufbau: Sequentieller Code: Code Proc1: Code Proc2:

call g

Sequentieller Code: Code Proc1: Code Proc2:

Page 9: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

9Optimierungstechniken in modernen Compilern Einführung

Warum soll der Compiler optimieren?

Optimierungen auf Quelltextebene (z.B. durch den Programmierer) sind möglich, machen es aber erforderlich, dass der Quelltext für jede Zielarchitektur optimiert wird.

Verschiedene Optimierungen, die auf Zielcodeebene erforderlich sind, lassen sich in einer Hochsprache nicht formulieren (z.B. Registerplanung):

Statisch geplante Architekturen:• Compiler führt Scheduling und Allokation durch – auf Quelltextebene in der

Regel nicht ausdrückbar Dynamisch geplante bzw. skalare Architekturen

• Compiler kann Hazards vermeiden helfen und Pipeline besser füllen• Nur ein kleines Fenster für die Optimierung in Hardware; Compiler kann

optimierbaren Code in dieses Fenster schieben SMP

• Compiler verteilt Programmcode und macht Parallelisierung möglich Programmiersprachen besitzen sequentielle Semantik; Geeignete

Form der Parallelität muss durch den Compiler erkannt werden: feingranular, grobgranular.

Page 10: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

10Optimierungstechniken in modernen Compilern Einführung

Demonstration dieser Problematik an einem Beispiel: Matrixmultiplikation

Optimal für eine skalare Architektur. Ergebnis der Multiplikation wird im Register für t akkumuliert.

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t = 0.0; for k = 1 to 100 step 1 do t = t + a[j][k] * b[k][i] od c[j][i] = t; odod

i = 1iLoop: j = 1jLoop: t = 0.0; k = 1kLoop: t = t + a[j][k] * b[k][i] k = k + 1 if k <= 100 then goto kLoop c[j][i] = t; j = j + 1 if j <= 100 then goto jLoop i = i + 1; if i <= 100 then goto iLoop

Page 11: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

11Optimierungstechniken in modernen Compilern Einführung

Was kann parallel ausgeführt werden?

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t = 0.0; for k = 1 to 100 step 1 do t = t + a[j][k] * b[k][i] od c[j][i] = t; odod

Basisblock enthält keine nennenswerte Parallelität

Iterationen der k-Schleife können nicht parallel ausgeführt werden: Iteration k+1 benötigt Wert von t aus Iteration k.

Iterationen der j-Schleife können nicht parallel ausgeführt werden: Benutzung derselben Variablen t.

Iterationen der i-Schleife können nicht parallel ausgeführt werden: Benutzung derselben Variablen t.

b

a cj

k

k

i

t

Page 12: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

12Optimierungstechniken in modernen Compilern Einführung

t

Scalar Expansion

Basisblock enthält keine nennenswerte Parallelität

Iterationen der k-Schleife können nicht parallel ausgeführt werden: Iteration k+1 benötigt Wert t[j] aus Iteration k.

Iterationen der j-Schleife können parallel ausgeführt werden, weil a und b nur gelesen werden und Akkumulation in unterschiedliche Elemente von t erfolgt.

Iterationen der i-Schleife können nicht parallel ausgeführt werden: Benutzung derselben Variablen t.

b

a cj

k

k

i

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od c[j][i] = t[j]; odod

t[j]

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t = 0.0; for k = 1 to 100 step 1 do t = t + a[j][k] * b[k][i] od c[j][i] = t; odod

Page 13: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

13Optimierungstechniken in modernen Compilern Einführung

Loop-Distribution

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; od for j = 1 to 100 step 1 do for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od od for j = 1 to 100 step 1 do c[j][i] = t[j]; odod

t

b

a cj

k

k

i

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od c[j][i] = t[j]; odod

Zuerst Vektor t initialisieren.

Werte in t berechnen.

Werte aus t nach c zurück schreiben.

Initialisieren, Berechnen und Zurückschreiben wurde separiert; kann aber nicht parallel ausgeführt werden.

Initialisieren, Berechnen und Zurückschreiben geschieht Elementweise in t.

Page 14: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

14Optimierungstechniken in modernen Compilern Einführung

Loop-Interchange

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; od for k = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od od for j = 1 to 100 step 1 do c[j][i] = t[j]; odod

t

b

a cj

k

k

i

Iterationen der inneren Schleife können parallel ausgeführt werden.

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; od for j = 1 to 100 step 1 do for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od od for j = 1 to 100 step 1 do c[j][i] = t[j]; odod

Keine nennenswerte Parallelität in der inneren Schleife, da jede Iteration den Wert t[j] aus der vorigen Iteration benötigt.

Page 15: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

15Optimierungstechniken in modernen Compilern Einführung

Möglichkeit der Vektorisierung (idealisiert)

for i = 1 to 100 step 1 do t[1..100] = 0.0; for k = 1 to 100 step 1 do t[1..100] = t[1..100]+a[1..100][k]*b[k][i] od c[1..100][i] = t[1..100];od

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; od for k = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od od for j = 1 to 100 step 1 do c[j][i] = t[j]; odod

t

b

a cj

k

k

i

Vektoroperation erfordert die parallele Ausführbarkeit der Operationen auf den Elemente des Vektors. Damit sind diese Operationen parallel auf einem superskalaren nicht-Vektor Prozessor ausführbar.

Page 16: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

16Optimierungstechniken in modernen Compilern Einführung

Möglichkeit der Vektorisierung (praktisch)

for i = 1 to 100 step 1 do t[1..100] = 0.0; for k = 1 to 100 step 1 do t[1..100] = t[1..100]+a[1..100][k]*b[k][i] od c[1..100][i] = t[1..100];od

for i = 1 to 100 step 1 do for j = 1 to 100 step 32 do t[j..j+31] = 0.0; od for k = 1 to 100 step 1 do for j = 1 to 100 step 32 do t[j..j+31] = t[j..j+31]+a[j..j+31][k]*b[k][i] od od for j = 1 to 100 step 32 do c[j..j+31][i] = t[j..j+31]; odod

t

b

a cj

k

k

i

Page 17: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

17Optimierungstechniken in modernen Compilern Einführung

Ausführung auf VLIW-Prozessor mit N Ausführungseinheiten

for i = 1 to 100 step 1 do for j = 1 to 100 step N do t[j] = 0.0; ... ; t[j+N-1] = 0.0; od for k = 1 to 100 step 1 do for j = 1 to 100 step N do t[j] = t[j]+a[j][k]*b[k][i]; ... t[j+N-1] = t[j+N-1]+a[j+N-1][k]*b[k][i]; od od for j = 1 to 100 step N do c[j][i] = t[j]; ... c[j+N-1][i] = t[j+N-1]; odod

N Multiplikationen und Additionen können parallel ausgeführt werden.

for i = 1 to 100 step 1 do for j = 1 to 100 step 32 do t[j..j+31] = 0.0; od for k = 1 to 100 step 1 do for j = 1 to 100 step 32 do t[j..j+31] = t[j..j+31]+a[j..j+31][k]*b[k][i] od od for j = 1 to 100 step 32 do c[j..j+31][i] = t[j..j+31]; odod

Page 18: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

18Optimierungstechniken in modernen Compilern Einführung

t1

Matrixmultiplikation für SMP mit zwei Prozessoren

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t = 0.0; for k = 1 to 100 step 1 do t = t + a[j][k] * b[k][i] od c[j][i] = t; odod

for i = 1 to 50 step 1 do for j = 1 to 100 step 1 do t0 = 0.0; for k = 1 to 100 step 1 do t0 = t0 + a[j][k] * b[k][i] od c[j][i] = t0; odod

for i = 51 to 100 step 1 do for j = 1 to 100 step 1 do t1 = 0.0; for k = 1 to 100 step 1 do t1 = t1 + a[j][k] * b[k][i] od c[j][i] = t1; odod

t0

b

aj

k

k

i

Page 19: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

19Optimierungstechniken in modernen Compilern Einführung

Grob- vs. feingranulare Parallelität

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; od for j = 1 to 100 step 1 do for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od od for j = 1 to 100 step 1 do c[j][i] = t[j]; odod t

b

a cj

k

k

iMatrixmultiplikation vor Loop-Interchange (keine feingranulare Parallelität in der inneren Schleife):

for j = 1 to 50 step 1 do for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] odod

for j = 51 to 100 step 1 do for k = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] odod

Aber äußere Schleife kann auf zwei verschiedenen Prozessoren verteilt werden.

t[j]

Page 20: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

20Optimierungstechniken in modernen Compilern Einführung

Grob- vs. feingranulare Parallelität

for i = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = 0.0; od for k = 1 to 100 step 1 do for j = 1 to 100 step 1 do t[j] = t[j]+a[j][k]*b[k][i] od od for j = 1 to 100 step 1 do c[j][i] = t[j]; odod t

b

a cj

k

k

i

Aufteilen der äußeren Schleife auf verschiedene Prozessoren führt zu gleichzeitigem Schreiben derselben Elemente in t. Ist also nicht möglich.

Matrixmultiplikation nach Loop-Interchange (viel feingranulare Parallelität in der inneren Schleife):

Page 21: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

21Optimierungstechniken in modernen Compilern Einführung

Aufgeworfene Fragen

Unter welchen Umständen ist eine bestimmte Transformation zulässig?

Welche Transformationen erzeugen fein granulare Parallelität, grob granulare Parallelität?

Wie kann die erzeugte fein granulare Parallelität in superskalaren Prozessorarchitekturen genutzt werden?

Wie kann die erzeugte grob granulare Parallelität in SMP Architekturen genutzt werden?

Page 22: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

22Optimierungstechniken in modernen Compilern Einführung

Aufbau der Vorlesung

Einleitung Grundlagen

Aufbau eines Compilers Überblick über die Analysephase Vorgehen bei einfacher Synthesephase Zwischencodeformate Datenflussanalyseschema Modellierung von Datenabhängigkeiten Abhängigkeitsanalyse

Page 23: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

23Optimierungstechniken in modernen Compilern Einführung

Aufbau der Vorlesung

Optimierungstechniken für DSPs und Mikrocontroller Globale Registerallokation Scheduling-Techniken Code-Selektion

Optimierunbgstechniken für superskalare Prozessoren Erzeugung fein granularer Parallelität Trade-Off Registerallokation/ILP Statische/Dynamische Parallelisierung HW-Support für bessere statische Parallelisierung Region-Based-Scheduling Global Code Motion Traces, Superblöcke, Hyperblöcke Modulo Scheduling IF-Conversion

Page 24: Vorlesung, Wintersemester 2009/10M. Schölzel 1 Optimierungstechniken in modernen Compilern Einführung

24Optimierungstechniken in modernen Compilern Einführung

Aufbau der Vorlesung

Optimierungstechniken für SMPs Erzeugung grob granularer Parallelität Parallelisierung ohne Synchronisierung Parallelisierung mit Synchronisierung (OpenMP)