Sebuah
implementasi VLIW akan
menghasilkan
efek
yang sama dengan superscalar RISC atau implementasi CISC, tapi desain VLIW melakukannya tanpa dua bagian yang paling kompleks dari desain superscalar berperforma
tinggi.
Karena instruksi VLIW secara eksplisit menentukan beberapa operasi independen yang secara eksplisit menentukan paralelisme, maka tidak diperlukan untuk melakukan decoding dan pengiriman hardware untuk merekonstruksi paralelisme dari aliran instruksi serial. Alih-alih berupaya untuk menemukan paralelisme, prosesor VLIW hanya akan mengandalkan compiler penghasil kode VLIW untuk secara eksplisit menentukan paralelisme. Mengandalkan kompilator memiliki kelebihan.
Pertama, compiler memiliki
kemampuan untuk melihat instruksi
dari
“jendela” yang jauh
lebih besar dari daripada perangkat keras. Untuk prosesor superscalar, jendela hardware yang lebih
besar
berdampak pada jumlah yang lebih besar dari logika dan area chip.
Pada beberapa titik, ada yang tidak cukup baik
sehingga
ukuran
jendela dibatasi. Lebih buruk
lagi,
bahkan
sebelum batas sederhana pada jumlah hardware tercapai, kompleksitas dapat berpengaruh
pada
kecepatan logika, sehingga ukuran jendela dibatasi untuk
menghindari berkurangnya kecepatan clock chip. Jendela software dapat menjadi besar. Dengan
demikian, mencari paralelisme di jendela perangkat
lunak
mungkin
untuk memperoleh hasil yang lebih baik.
Kedua, compiler memperoleh pengetahuan dari kode sumber program. Source code biasanya berisi informasi penting tentang perilaku program yang dapat digunakan untuk membantu paralelisme maksimum untuk diungkapkan pada tingkat instruksi-set. Sebuah teknik yang kuat yang disebut jejak-driven kompilasi dapat digunakan untuk meningkatkan kualitas output kode kompilator secara dramatis. Jejak-drive kompilasi pertama menghasilkan sebuah program VLIW yang belum optimal, tapi benar. Program ini telah menanamkan rutinitas yang mencatat perilaku program. Catatan perilaku program yang diambil, seperti berapa percabangan yang diambil dan seberapa sering, digunakan oleh compiler selama kompilasi kedua untuk menghasilkan kode yang mengambil manfaat dari informasi yang akurat tentang perilaku program. Dengan memiliki jejak-arah kompilasi, compiler memiliki akses ke beberapa informasi dinamis yang akan mempermudah logika pengiriman hardware dalam prosesor superscalar.
Ketiga, dengan register yang memadai dapat ditiru fungsi implementasi superscalar reorder buffer.
Tujuan dari buffer menyusun ulang adalah untuk memungkinkan prosesor
superscalar untuk mengeksekusi instruksi spekulatif dan kemudian dapat dengan
cepat membuang hasil spekulatif jika perlu. Dengan register yang cukup, mesin
VLIW dapat menempatkan hasil instruksi spekulatif yang dieksekusi pada register sementara.
Compiler mengetahui berapa banyak instruksi yang akan dieksekusi secara spekulatif, sehingga hanya akan menggunakan register dengan berspekulasi sepanjang jalur (yang diprediksi) dan mengabaikan nilai-nilai pada register tersebut di sepanjang jalur yang akan diambil jika percabangan tersebut ternyata telah salah memprediksi.
Gambar dibawah ini menunjukkan implementasi VLIW secara umum, tanpa reorder buffer yang kompleks serta pengiriman logika.
Implementasi VLIW Secara Umum
Bagaimana VLIW Bekerja
Arsitektur VLIW merupakan solusi sebaliknya dari
superscalar. Dimana arsitektur ini akan mereduksi beberapa penggunaan hardware
yang kompleks seperti Instruction Windows
untuk mendeteksi paralelisme.
Dengan tidak adanya Instruction
Windows apakah arsitektur VLIW masih mampu melakukan prediksi paralelisme?
Jawabannya adalah YA.
Tidak seperti halnya pada arskitektur superscalar yang memprediksi
paralelisme pada saat run-time program yaitu dengan memasukkan setiap instruksi
dan juga prediksi percabangan (branch
prediction) kedalam instruction windows kemudian baru
diprediksi paralelismenya, arsitektur VLIW justru memprediksinya pada saat
compile-time. Program secara keseluruhan oleh compiler akan memprediksi operasi
yang dapat diparalelkan kemudian operasi tersebut akan dikelompokkan
masing-masing kedalam sebuah instruksi yang “sangat besar” (instruksi inilah
yang kita sebut dengan Very Large Instruction Word) yang memiliki panjang
tetap. Kemudian instruksi yang tergabung ini akan dieksekusi secara parallel.
Catatan: arsitektur VLIW sangat
bergantung pada kapabilitas Compiler!
Teknik compiler guna menambah potensi paralelisme antara
lain:
è Loop
Unrolling
è Trace
Schedulling
A.
Loop
Unrolling
Loop unrolling merupakan teknik yang dilakukan oleh
compiler untuk meningkatkan potensi paralelisme, yaitu dengan cara menuliskan
statement didalam loop beberapa kali.
for(i=959;i>=0;i--)
{
x[i] = x[i]+s;
}
|
Program
tersebut akan dikompilasi menjadi:
-asumsikan bahwa register R1 telah
menyimpan alamat elemen terakhir x, dan elemen lainnya disimpan pada alamat
dibawahnya secara berurut, sehingga x[0] berada pada alamat 0.
Loop:
LDD F0,
(R1) F0 <- x[i] ;(load
double)
ADF F4,F0,F2
F4 <- F0 + F2 ;(floating pnt)
STD (R1),F4
x[i] <- F4 ;(store double)
SBI R1,R1,#8 R1
<- R1 - 8
BGEZ R1,Loop
CYCLE TIME TABLE
Hasilnya:
- 1
iterasi = 6cycle
-
total iterasi = 960*6 = 5760cycle
ASUMSI: Prosesor VLIW yang digunakan
memiliki rule dimana 1 clock cycle dapat dilakukan 2 operasi memory reference,
2 operasi floating point, dan 1 operasi integer/percabangan. Dimana untuk
proses load untuk double-word (DW), member tambahan 1 cycle dan operasi
floating point member tambahan 2 cycle.
Dengan
teknik loop unrolling, kode tersebut
dapat ditulis ulang menjadi:
for(i=959;i>=0;i-=2)
{
x[i] = x[i]+s;
x[i-1] = x[i-1]+s;
}
|
Kompilasi
kode:
Loop:
LDD F0, (R1) F0 <- x[i] ;(load double)
ADF F4,F0,F2
F4 <- F0 + F2 ;(floating pnt)
STD (R1),F4
x[i] <- F4 ;(store double)
LDD F0,
-8(R1) F0 <- x[i-1] ;(load
double)
ADF F4,F0,F2
F4 <- F0 + F2 ;(floating pnt)
STD -8(R1),F4
x[i-1] <- F4 ;(store double)
SBI R1,R1,#16 R1
<- R1 - 16
BGEZ R1,Loop
CYCLE TIME TABLE
Hasilnya:
- 2
iterasi = 6cycle
-
total iterasi = (960/2)*6 = 2880cycle
Begitu seterusnya, sehingga dengan melakukan loop
unrolling akan meningkatkan paralelisme dan memperkecil kebutuhan cycle time.
Namun teknik loop unrolling juga memiliki batasan, karena dengan menambah
unroll maka akan membuat program menjadi bertambah besar dan berimbas pada
bertambahnya kebutuhan memori untuk menyimpan program tersebut, juga semakin
banyak unroll yang dilakukan akan menambah jumlah register yang dibutuhkan
sehingga akan meningkatkan traffic pada pengaksesan register.
Trace Scheduling
Trace scheduling merupakan teknik lain yang
dilakukan untuk mengoptimalkan paralelisme. Teknik ini dilakukan pada operasi
percabangan.
Program secara umum dapat dideskripsikan melalui sebuah
graf, dimana setiap node menunjukkan operasi (atau sering disebut dengan program flow graph). Trace merupakan jalur nonsiklik yang
melalui graf tersebut. Tujuan utama trace scheduling adalah untuk mencari trace
yang paling optimal.
Trace scheduling terdiri dari 3 tahapan, yaitu:
-
Pemilihan Trace (Trace
Selection)
-
Instruction Scheduling
-
Compensation and Replacement
a. Trace
Selection
Dalam
tahapan ini dipilih jalur yang paling sering dieksekusi / dilalui.
Contoh
program:
if(c!=0)
{
b
= a / c;
}
else
{
b
= 0; h=0;
}
f = g +
h;
|
Maka,
hasil kompilasi program menjadi:
LD R0, c R0 <- c ;(load word)
BZ R0,Else
LD
R1, a R1 <- a ;(load integer)
DV
R1,R1,R0 R1 <- R1 / R0 ;(integer)
ST b,R1 b
<- R1 ;(store word)
BR Next
Else: STI b,#0 b
<- 0
STI
h,#0 h
- 0
Next:
LD R0, g R0
<- g ;(load word)
LD
R1, h R1 <- h ;(load word)
AD
R1,R1,R0 R1 <- R1 + R0 ;(integer)
ST f,R1 f
<- R1 ;(store word)
EndIF:
- - - - - - - - - - - - - - -
Representasi
node:
INSTRUKSI
|
NODE
|
INSTRUKSI
|
NODE
|
LD R0,c
|
A
|
STI h,#0
|
G
|
BZ R0,Else
|
B
|
LD R0,g
|
H
|
LD R1,a
|
C
|
LD R1,h
|
I
|
DV R1,R1,R0
|
D
|
AD R1,R1,R0
|
J
|
ST b,R1
|
E
|
ST f,R1
|
K
|
STI b,#0
|
F
|
|
|
b. Instruction
Scheduling
Pada
tahap ini trace yang telah dipilih akan dijadwalkan kedalam operasi parallel
pada prosesor VLIW.
c. Replacement
and Compensation
Pada
tahap ini, compensation code ditambahkan bertujuan untuk menjaga agar program
tetap konsisten/benar.
Contoh
kondisi yang membutuhkan compensation code:
- - Pada
cycle kedua, proses load nilai g dan h dilakukan sebelum kondisi percabangan.
- - Pada
cycle pertama, proses load nilai a juga dilakukan sebelum kondisi percabangan.
- - Pada
cycle keempat, proses store nilai pada b setelah proses percabangan (berada
pada bagian next)
Solusinya adalah dengan menambahkan
kode else dan compensation code:
CATATAN: ditambahkan compensation
code (tambahan kode) karena, R3 meng-load nilai h sebelum percabangan sehingga
agar nilai yg didapat tetap benar maka pada Register R3 diisi dengan nilai 0
(sesuai kondisi Else dimana h=0).
Intel Itanium Processor
Itanium-1 prosesor
64-bit, memiliki 6 keluaran dari VLIWprocessor dengan empat
unit integer, empat
unit multimedia, dua load / store unit, dua
unit presisi floating
point yang diperpanjang dan dua unit single floating
point presisi. Arsitektur Intel Itenium ditunjukkan
pada Gambar dibawah ini.
Arsitektur Intel
Itanium
Prosesor ini berjalan pada processor 800 MHz dengan proses 0,18
mikron dan memiliki pipa 10 tahap. Setiap MultiOp terdiri
dari satu atau lebih 128 bit bundel. Setiap
128 bit bundel tersebut terdiri dari tiga operasi
dan contoh. Contoh meng-encode kombinasi umum dari jenis-jenis operasi. Karena bidang
template hanya memiliki lebar 5 bit, bundel
tidak mendukung semua kemungkinan kombinasi jenis instruksi. Ada 128
register tujuan umum dan satu set lainnya dari 128, 82-bit floating point register berukuran lebar. Gambaran format instruksi
ditunjukkan pada Gambar dibawah ini.
Format
Instuksi Intel Itanium
Modul penjadwalan adalah teknik
pipelining pada software yang
dapat mendukung tumpang tindih dari eksekusi loop
untuk
mengurangi “ekor” dari kode. Dalam sebuah unit pipeline,
setiap tahap memegang perhitungan dan
setiap unit data dapat diterapkan untuk fungsi unit sebelumnya dimana data tersebut telah benar-benar
diproses. Untuk mengambil keuntungan dari operasi pipeline, dalam sebuah modul loop, loop akan terbuka dan dibagi
menjadi beberapa tahap. Compiler dapat menjadwalkan beberapa iterasi dari
sebuah loop secara pipeline asalkan
data output dari satu tahap mengalir
masuk ke
tahap berikutnya dalam pipa software. Secara tradisional, ini pembukaan loop ini
memerlukan penggantian nama register dalam iterasi berturut-turut.
Untuk
mendukung spekulasi data, processor mendukung jenis
khusus dari beban yang disebut
advance load. Jika compiler tidak
dapat enghubungkan antara alamat toko dan beban kemudian, dapat
mengeluarkan beban muka depan toko.
Prosesor menggunakan struktur hardware khusus yang disebut ALAT untuk melacak apakah
sebuah toko kemudian menulis ke lokasi yang sama dengan beban muka.
Pada lokasi asli di mana beban telah secara alami ditempatkan, compiler menyisipkan operasi pemeriksaan khusus untuk melihat apakah sebuah penyimpanan membatalkan hasil dari beban. Jika beban muka tidak disahkan, dilakukan operasi pemeriksaan untuk mengontrol transfer ke kode pemulihan.
Hal ini mendukung kedua petunjuk statis dan dinamis dari percabangan serta penggunaan hardware untuk memprediksi percabangan. Ada juga petunjuk dalam instruksi beban dan penyimpanan yang menginformasikan prosesor tentang perilaku cache pada operasi memori tertentu.
Intel Itanium 2 Processor
Prosesor Intel Itanium 2 adalah
implementasi kedua dari Itanium Instruction Set Architecture (ISA). Prosesor
Itanium 2 terdiri dari 6-wide, 8-stage deep pipeline yang berjalan antara 1.0
GHz atau 900MHz. Terdiri dari 6 unit integer, 6 unit multimedia, dua unit load
dan store, 3 unit branch, dua unit extended-precision floating-point, dua
tambahan unit single-precision floating-point. Hardwarenya tediri dari dynamic
prefetch, branch prediction, sebuah scoreboard register, dan non-blocking
cache. Tiga level on-die cache, L1, L2, L3 untuk meminimalisir latensi memori
secara keseluruhan. Teridiri dari 3 MB atau 1,5 MB L3 cache, dengan data
bandwidth 32 GB/cycle. System bus didesain untuk glueless MP support hingga 4
processor per system bus, dan dapat digunakan sebagai building block yang
efektif untuk sistem yang berskala besar. Arsitektur Intel Itanium 2 dapat
dilihat pada Gambar dibawah ini.
Arsitektur Prosesor Intel
Itanium 2
Keuntungan dari Kompleksitas Compiler atas Kompleksitas Hardware
Ketika arsitektur VLIW mengurangi
kompleksitas hardware selama implementasi superscalar, compiler
yang
jauh
lebih kompleks tetap diperlukan. Pengembangan
implementasi
dari
kinerja
maksimum pada superscalar RISC atau CISC tidak memperoleh teknik compiler
yang
canggih, tetapi tingkat kecanggihan dalam compiler VLIW secara
signifikan lebih tinggi.
VLIW hanya bergerak secara kompleks dari perangkat
keras ke perangkat lunak. Trade-off ini memiliki sisi manfaat yang
signifikan: kompleksitas hanya dilakukan
sekali, ketika
compiler tidak ditulis setiap kali chip ini dipabrikasi. Diantara manfaatnya adalah diperoleh sebuah chip yang lebih
kecil sehingga meningkatkan keuntungan bagi vendor mikroprosesor dan harga yang lebih murah bagi pelanggan yang
menggunakannya. Kompleksitas biasanya lebih mudah ditangani dalam desain perangkat
lunak dari pada hardware. Dengan
demikian, akan lebih sedikit biaya
untuk merancang, lebih cepat
untuk
mendesain, dan lebih
sedikit memerlukan debugging. Semua
itu
adalah
faktor-faktor yang dapat membuat desain
mikroprossor menjadi lebih murah. Selain
itu,
perbaikan compiler dapat dilakukan
setelah chip telah dibuat. Sementara perbaikan pada hardware superscalar memerlukan
perubahan pada mikroprosesor, yang secara
alami
akan menimbulkan biaya
besar
untuk
mengubah desain chip.
Implementasi Arsitektur VLIW
Format instruksi VLIW yang paling sederhana mengkodekan operasi
untuk setiap unit eksekusi pada
mesin. Hal ini wajar dengan asumsi setiap
instruksi akan selalu memiliki sesuatu yang berguna untuk melakukan setiap eksekusi. Namun, meskipun
dengan algoritma compiler
yang terbaik, biasanya tidak mungkin untuk mengirimkan setiap instruksi ke semua unit eksekusi. Selain itu, pada mesin VLIW yang memiliki unit eksekusi integer dan floating-point,
compiler terbaik tidak akan mampu untuk
menjaga unit floating point selalu sibuk selama pelaksanaan
aplikasi integer.
Masalah dengan instruksi seperti itu tidak membuat penuh penggunaan semua unit eksekusi sehingga membuang sumber daya processor: instruksi ruang memori, ruang instruksi cache, dan bandwidth bus.
Setidaknya ada dua solusi
untuk mengurangi
pemborosan sumber daya karena instruksi yang jarang. Pertama, instruksi dapat dikompresi dengan
representasi yang sangat-encoded. Sejumlah teknik, seperti kode Huffman dapat
digunakan untuk
mengalokasikan bit yang paling
sedikit pada
operasi yang paling sering digunakan.
Kedua, kemungkinan untuk mendefinisikan kata instruksi dengan mengkode lebih sedikit operasi dibandingkan jumlah eksekusi yang tersedia. Bayangkan mesin VLIW dengan sepuluh eksekusi tapi instruksinya hanya dapat menjalankan lima operasi. Dalam skema ini, sejumlah unit dikodekan bersamaan dengan operasi dan menentukan unit eksekusi mana yang seharusnya dikirimkan. Manfaatnya adalah pada penggunaan sumber daya yang lebih baik. Masalah potensialnya adalah instruksi yang pendek membatasi mesin dalam mengerjakan jumlah maksimum operasi pada satu waktu. Untuk mencegah masalah pembatasan kinerja ini, ukuran dari kata instruksi dapat disesuaikan berdasarkan analisis simulasi atau perilaku program.
Tentu saja, sangat mungkin untuk menggabungkan teknik lainnya: menggunakan kompresi yang lebih pendek dari panjang instruksi maksimum.
Conclusion:
- Implementasi VLIW highly parallel lebih sederhana dan lebih murah dibandingkan yang sejenisnya yaitu RISC dan CISC;
- Encoding dari VLIW word melibatkan paralelisme terhadap instruksi primitif, yang dapat mengurangi hardware complexity seperti pada arsitektur superscalar;
- Compiler harus menggabungkan beberapa instruksi primitif menjadi sebuah VLIW word, untuk memastikan semua function unit tidak idle;
- Compiler melakukan optimasi pipeline secara software, dengan melakukan re-ordering untuk mecapai tingkat paralelisme tertinggi dalam sequential code;
- Kinerja Microprosesor tergantung dari bagaimana cara compiler menghasilkan VLIW words.
No comments:
Post a Comment